diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index bc632c10d139..9b1e62da8cd4 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -12,6 +12,7 @@ - [WEAR] Updated UserAgent of API requests to use `http.agent` System Property to fix performance issues related to WebView usage on app launch [https://github.com/woocommerce/woocommerce-android/pull/14431] - [***] POS: A new settings to customize the POS [https://github.com/woocommerce/woocommerce-android/pull/14527] - [*] [Login] Improved the detection of WooCommerce API version during login flow [https://github.com/woocommerce/woocommerce-android/pull/14524] +- [*] Shipping Labels: Adds caching to the "Select a Package" screen [https://github.com/woocommerce/woocommerce-android/pull/14541] - [*] Add more filter options to orders filters sales channel [https://github.com/woocommerce/woocommerce-android/pull/14546] - [*] Automatically populate the weight field in the create shipment flow [https://github.com/woocommerce/woocommerce-android/pull/14525] - [*] [Shipping Labels] Fixed displaying incorrect hazardous material option for purchased labels [https://github.com/woocommerce/woocommerce-android/pull/14571] diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/WooShippingLabelPackageCreationViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/WooShippingLabelPackageCreationViewModel.kt index 99c6efcaceca..4255ad24096d 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/WooShippingLabelPackageCreationViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/WooShippingLabelPackageCreationViewModel.kt @@ -13,7 +13,8 @@ import com.woocommerce.android.analytics.AnalyticsTracker.Companion.VALUE_STARTE import com.woocommerce.android.analytics.AnalyticsTrackerWrapper import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.orders.wooshippinglabels.models.StoreOptionsModel -import com.woocommerce.android.ui.orders.wooshippinglabels.packages.datasource.FetchPackagesFromStore +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.datasource.FetchShippingPackages +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.datasource.ObserveShippingPackages import com.woocommerce.android.ui.orders.wooshippinglabels.packages.datasource.WooShippingLabelPackageRepository import com.woocommerce.android.ui.orders.wooshippinglabels.packages.networking.CustomPackageCreationRequestData import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.Carrier @@ -27,7 +28,9 @@ import com.woocommerce.android.viewmodel.ScopedViewModel import com.woocommerce.android.viewmodel.getStateFlow import com.woocommerce.android.viewmodel.navArgs import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.shareIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlinx.parcelize.Parcelize @@ -39,12 +42,15 @@ class WooShippingLabelPackageCreationViewModel @Inject constructor( savedState: SavedStateHandle, private val selectedSite: SelectedSite, private val resourceProvider: ResourceProvider, - private val fetchPackages: FetchPackagesFromStore, + observeShippingPackages: ObserveShippingPackages, + private val fetchShippingPackages: FetchShippingPackages, private val updateSavedCarrierPackages: UpdateSavedCarrierPackages, private val packageRepository: WooShippingLabelPackageRepository, private val tracker: AnalyticsTrackerWrapper, ) : ScopedViewModel(savedState) { private val navArgs: WooShippingLabelPackageCreationFragmentArgs by savedState.navArgs() + private val shippingPackagesFlow = observeShippingPackages() + .shareIn(viewModelScope, started = SharingStarted.Lazily, replay = 1) private val _viewState = savedState.getStateFlow( scope = viewModelScope, @@ -72,20 +78,16 @@ class WooShippingLabelPackageCreationViewModel @Inject constructor( ) init { - loadData() - } - - private fun loadData(): Job { - return launch { - tracker.track(AnalyticsEvent.WCS_PACKAGE_SELECTION_STEP, mapOf(KEY_STATE to VALUE_STARTED)) - fetchPackages().let { response -> - _viewState.update { viewState -> viewState.copy(packagesState = response) } - if (response is PackagesState.Data) { + tracker.track(AnalyticsEvent.WCS_PACKAGE_SELECTION_STEP, mapOf(KEY_STATE to VALUE_STARTED)) + launch { + shippingPackagesFlow.collectLatest { packages -> + _viewState.update { viewState -> viewState.copy(packagesState = packages) } + if (packages is PackagesState.Data) { tracker.track(AnalyticsEvent.WCS_PACKAGE_SELECTION_STEP, mapOf(KEY_STATE to "loading_success")) - } else if (response is PackagesState.Error) { + } else if (packages is PackagesState.Error) { tracker.track( AnalyticsEvent.WCS_PACKAGE_SELECTION_STEP, - mapOf(KEY_STATE to "loading_failed", KEY_ERROR to response.error) + mapOf(KEY_STATE to "loading_failed", KEY_ERROR to packages.error) ) } } @@ -148,7 +150,7 @@ class WooShippingLabelPackageCreationViewModel @Inject constructor( fun onRetryClick() { triggerEvent(ShowLoadingDialog(true)) launch { - loadData().join() + fetchShippingPackages() triggerEvent(ShowLoadingDialog(false)) } } @@ -333,7 +335,7 @@ class WooShippingLabelPackageCreationViewModel @Inject constructor( return response.takeIf { it.isError.not() } ?.model?.firstOrNull() - ?.let { PackageData.fromPackageDAO(it) } + ?.let { PackageData.fromPackageEntity(it) } ?.let { Result.success(it) } ?: Result.failure(Throwable(response.error.type.toString())) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/FetchPackagesFromStore.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/FetchPackagesFromStore.kt deleted file mode 100644 index c03f83b33a40..000000000000 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/FetchPackagesFromStore.kt +++ /dev/null @@ -1,67 +0,0 @@ -package com.woocommerce.android.ui.orders.wooshippinglabels.packages.datasource - -import com.woocommerce.android.tools.SelectedSite -import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.PackagesState -import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.Carrier -import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.CarrierPackageGroup -import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.PackageData -import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.StoreOptionsForPackages -import javax.inject.Inject - -class FetchPackagesFromStore @Inject constructor( - private val selectedSite: SelectedSite, - private val packageRepository: WooShippingLabelPackageRepository -) { - suspend operator fun invoke(): PackagesState { - val result = packageRepository.fetchAllStorePackages(selectedSite.get()) - val model = result.model - return if (!result.isError && model != null) { - val storePackages = model - PackagesState.Data( - storeOptions = storePackages.storeOptions.toStoreOptionsForPackages(), - savedPackages = storePackages.savedPackages.map { PackageData.fromPackageDAO(it) }, - carrierPackages = storePackages.filterCarrierData() - ) - } else { - PackagesState.Error(result.error.type.name) - } - } - - private fun StorePackagesDAO.filterCarrierData(): Map> { - val result = mutableMapOf>() - carrierPackages.parseCarrierData(CarrierType.USPS).takeIf { it.isNotEmpty() }?.let { carrierData -> - result[Carrier.USPS] = carrierData - } - - carrierPackages.parseCarrierData(CarrierType.DHL).takeIf { it.isNotEmpty() }?.let { carrierData -> - result[Carrier.DHL] = carrierData - } - - carrierPackages.parseCarrierData(CarrierType.UPS).takeIf { it.isNotEmpty() }?.let { carrierData -> - result[Carrier.UPS] = carrierData - } - - return result - } - - private fun StoreOptionsDAO.toStoreOptionsForPackages() = - StoreOptionsForPackages( - currencySymbol = currencySymbol, - dimensionUnit = dimensionUnit, - weightUnit = weightUnit, - originCountry = originCountry - ) - - private fun Map.parseCarrierData( - carrierType: CarrierType - ) = get(carrierType)?.let { - it.packageGroup.map { group -> - CarrierPackageGroup( - groupName = group.description, - packages = group.packages.map { packageItem -> - PackageData.fromPackageDAO(packageItem) - } - ) - } - } ?: emptyList() -} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/FetchShippingPackages.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/FetchShippingPackages.kt new file mode 100644 index 000000000000..29e90bc51b59 --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/FetchShippingPackages.kt @@ -0,0 +1,21 @@ +package com.woocommerce.android.ui.orders.wooshippinglabels.packages.datasource + +import com.woocommerce.android.tools.SelectedSite +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity +import javax.inject.Inject + +class FetchShippingPackages @Inject constructor( + private val packageRepository: WooShippingLabelPackageRepository, + private val selectedSite: SelectedSite +) { + suspend operator fun invoke(): Result { + val response = packageRepository.fetchShippingPackages(selectedSite.get()) + val result = response.model + return if (response.isError || result == null) { + val message = response.error?.type?.name ?: "Unknown error" + Result.failure(Exception(message)) + } else { + Result.success(result) + } + } +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/ObserveShippingPackages.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/ObserveShippingPackages.kt new file mode 100644 index 000000000000..7d6bf44d5975 --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/ObserveShippingPackages.kt @@ -0,0 +1,88 @@ +package com.woocommerce.android.ui.orders.wooshippinglabels.packages.datasource + +import com.woocommerce.android.tools.SelectedSite +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.PackagesState +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.Carrier +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.CarrierPackageGroup +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.PackageData +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.StoreOptionsForPackages +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.transformLatest +import kotlinx.coroutines.flow.withIndex +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity.CarrierPackageGroups +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity.StoreOptions +import javax.inject.Inject + +class ObserveShippingPackages @Inject constructor( + private val selectedSite: SelectedSite, + private val packageRepository: WooShippingLabelPackageRepository, + private val fetchShippingPackages: FetchShippingPackages +) { + @OptIn(ExperimentalCoroutinesApi::class) + operator fun invoke(): Flow = packageRepository.observeShippingPackages(selectedSite.get()) + .withIndex() + .transformLatest { (index, entity) -> + val isFirst = index == 0 + when { + isFirst && entity == null -> { + val result = fetchShippingPackages() + if (result.isFailure) { + emit(PackagesState.Error(result.exceptionOrNull()?.message ?: "Unknown error")) + } + } + + entity == null -> emit(PackagesState.Error()) + else -> { + emit(entity.toPackagesState()) + if (isFirst) { + fetchShippingPackages() + } + } + } + } + + private fun StoreOptions.toStoreOptionsForPackages() = StoreOptionsForPackages( + currencySymbol = currencySymbol ?: StoreOptionsForPackages.DEFAULT.currencySymbol, + dimensionUnit = dimensionUnit ?: StoreOptionsForPackages.DEFAULT.dimensionUnit, + weightUnit = weightUnit ?: StoreOptionsForPackages.DEFAULT.weightUnit, + originCountry = originCountry ?: StoreOptionsForPackages.DEFAULT.originCountry + ) + + private fun WooShippingPackagesEntity.filterCarrierData(): Map> = + buildMap { + carrierPackageGroups.parseCarrierData(WooShippingPackagesEntity.CarrierType.USPS) + .takeIf { it.isNotEmpty() } + ?.let { packageGroups -> put(Carrier.USPS, packageGroups) } + + carrierPackageGroups.parseCarrierData(WooShippingPackagesEntity.CarrierType.DHL) + .takeIf { it.isNotEmpty() } + ?.let { packageGroups -> put(Carrier.DHL, packageGroups) } + + carrierPackageGroups.parseCarrierData(WooShippingPackagesEntity.CarrierType.UPS) + .takeIf { it.isNotEmpty() } + ?.let { packageGroups -> put(Carrier.UPS, packageGroups) } + } + + private fun List.parseCarrierData( + carrierType: WooShippingPackagesEntity.CarrierType + ) = find { it.carrierType == carrierType }?.let { + it.packageGroups?.mapNotNull { group -> + group.description?.let { description -> + CarrierPackageGroup( + groupName = description, + packages = group.packages?.map { packageItem -> + PackageData.fromPackageEntity(packageItem) + }.orEmpty() + ) + } + } + } ?: emptyList() + + private fun WooShippingPackagesEntity.toPackagesState() = PackagesState.Data( + storeOptions = storeOptions.toStoreOptionsForPackages(), + savedPackages = savedPackages.map { PackageData.fromPackageEntity(it) }, + carrierPackages = filterCarrierData() + ) +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/PackageDAOs.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/PackageDAOs.kt deleted file mode 100644 index 38a23b13591f..000000000000 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/PackageDAOs.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.woocommerce.android.ui.orders.wooshippinglabels.packages.datasource - -data class StorePackagesDAO( - val storeOptions: StoreOptionsDAO, - val savedPackages: List, - val carrierPackages: Map -) - -data class PackageDAO( - val id: String, - val name: String, - val dimensions: String, - val weight: String, - val isLetter: Boolean, - val dimensionUnit: String, - val isUserDefined: Boolean = false, - val weightUnit: String, - val groupName: String? = null, - val saved: Boolean, -) - -data class CarrierDAO( - val packageGroup: List -) - -data class CarrierPackageGroupDAO( - val description: String, - val packages: List -) - -data class StoreOptionsDAO( - val currencySymbol: String, - val dimensionUnit: String, - val weightUnit: String, - val originCountry: String -) - -enum class CarrierType(val id: String) { - USPS(id = "usps"), - DHL(id = "dhlexpress"), - UPS(id = "upsdap"); - - companion object { - fun fromId(id: String): CarrierType? = entries.firstOrNull { it.id == id } - } -} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/WooShippingLabelPackageMapper.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/WooShippingLabelPackageMapper.kt index 4e32f66762ca..17c4c425f303 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/WooShippingLabelPackageMapper.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/WooShippingLabelPackageMapper.kt @@ -6,61 +6,68 @@ import com.woocommerce.android.ui.orders.wooshippinglabels.packages.networking.P import com.woocommerce.android.ui.orders.wooshippinglabels.packages.networking.PackageResponse import com.woocommerce.android.ui.orders.wooshippinglabels.packages.networking.PackageStoreOptionsDTO import com.woocommerce.android.ui.orders.wooshippinglabels.packages.networking.SavedPackageInfoDTO +import org.wordpress.android.fluxc.model.SiteModel +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity.CarrierPackageGroup +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity.CarrierPackageGroups +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity.CarrierType +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity.Package +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity.StoreOptions import javax.inject.Inject class WooShippingLabelPackageMapper @Inject constructor() { - operator fun invoke(response: PackageResponse): StorePackagesDAO { - val savedPackageInfoDTO = response.packages?.saved + operator fun invoke(site: SiteModel, response: PackageResponse): WooShippingPackagesEntity { val storeOptionsResponse = response.storeOptions ?: PackageStoreOptionsDTO() - val carrierPackages = mapCarrierPackages( - response.storeOptions, - response.packages?.predefined, - response.packages?.saved?.predefined + val savedPackageInfoDTO = response.packages?.saved + val carrierPackageGroups = mapCarrierPackages( + storeOptions = response.storeOptions, + carrierPackagesResponse = response.packages?.predefined, + savedCarrierPackageIds = response.packages?.saved?.predefined ) - return StorePackagesDAO( + return WooShippingPackagesEntity( + localSiteId = site.localId(), storeOptions = mapStoreOptions(storeOptionsResponse), savedPackages = savedPackageInfoDTO?.let { - mapSavedPackages(it, response.storeOptions, carrierPackages) + mapSavedPackages( + savedPackageInfoDTO = it, + storeOptions = response.storeOptions, + carrierPackageGroups = carrierPackageGroups + ) } ?: emptyList(), - carrierPackages = carrierPackages + carrierPackageGroups = carrierPackageGroups ) } - operator fun invoke( - response: PackageCreationResponse - ): List { - return response.custom?.map { - PackageDAO( - id = it.id.orEmpty(), - name = it.name.orEmpty(), - dimensions = it.dimensions.orEmpty(), - weight = it.boxWeight?.toString().orEmpty(), - isLetter = it.isLetter ?: false, - isUserDefined = it.isUserDefined == true, - dimensionUnit = "", - weightUnit = "", - saved = true - ) - } ?: emptyList() - } + operator fun invoke(site: SiteModel, response: PackageCreationResponse): List = response.custom?.map { + Package( + id = it.id.orEmpty(), + name = it.name.orEmpty(), + dimensions = it.dimensions.orEmpty(), + weight = it.boxWeight?.toString().orEmpty(), + isLetter = it.isLetter ?: false, + isUserDefined = it.isUserDefined == true, + dimensionUnit = "", + weightUnit = "", + saved = true + ) + } ?: emptyList() private fun mapSavedPackages( savedPackageInfoDTO: SavedPackageInfoDTO, storeOptions: PackageStoreOptionsDTO?, - carrierPackages: Map? - ): List { + carrierPackageGroups: List? + ): List { val savedCarrierPackages = savedPackageInfoDTO.predefined?.flatMap { (carrierId, packageIds) -> val carrier = CarrierType.fromId(carrierId) - val allPackagesForCarrier = carrierPackages?.get(carrier) - ?.packageGroup - ?.flatMap { it.packages } + val allPackagesForCarrier = carrierPackageGroups?.find { it.carrierType == carrier }?.packageGroups + ?.flatMap { it.packages.orEmpty() } packageIds.mapNotNull { packageId -> allPackagesForCarrier?.find { it.id == packageId } } } ?: emptyList() val savedCustomPackages = savedPackageInfoDTO.custom?.map { - PackageDAO( + Package( id = it.id.orEmpty(), name = it.name.orEmpty(), dimensions = it.dimensions.orEmpty(), @@ -79,56 +86,53 @@ class WooShippingLabelPackageMapper @Inject constructor() { storeOptions: PackageStoreOptionsDTO?, carrierPackagesResponse: CarrierPredefinedPackagesDTO?, savedCarrierPackageIds: Map>?, - ): Map { - val uspsPackages = buildList { - carrierPackagesResponse?.usps?.let { usps -> - usps.flatBoxes?.toCarrierGroup(storeOptions, savedCarrierPackageIds?.get(CarrierType.USPS.id)) - ?.let { add(it) } - usps.boxes?.toCarrierGroup(storeOptions, savedCarrierPackageIds?.get(CarrierType.USPS.id)) - ?.let { add(it) } - usps.expressBoxes?.toCarrierGroup(storeOptions, savedCarrierPackageIds?.get(CarrierType.USPS.id)) - ?.let { add(it) } - usps.envelopes?.toCarrierGroup(storeOptions, savedCarrierPackageIds?.get(CarrierType.USPS.id)) - ?.let { add(it) } + ): List { + fun groupsFor( + type: CarrierType, + groups: List + ): CarrierPackageGroups? { + val savedIds = savedCarrierPackageIds?.get(type.id) + val mapped = groups + .filterNotNull() + .map { it.toCarrierGroup(storeOptions, savedIds) } + return mapped.takeIf { it.isNotEmpty() }?.let { + CarrierPackageGroups(type, it) } } - val dhlPackages = buildList { - carrierPackagesResponse?.dhlExpress?.let { dhl -> - dhl.domesticAndInternationalPackages - ?.toCarrierGroup(storeOptions, savedCarrierPackageIds?.get(CarrierType.DHL.id)) - ?.let { add(it) } - } - } + val usps = carrierPackagesResponse?.usps + val dhl = carrierPackagesResponse?.dhlExpress + val ups = carrierPackagesResponse?.ups - val upsPackages = buildList { - carrierPackagesResponse?.ups?.let { ups -> - ups.domesticAndInternationalPackages - ?.toCarrierGroup(storeOptions, savedCarrierPackageIds?.get(CarrierType.UPS.id)) - ?.let { add(it) } + return listOfNotNull( + usps?.let { + groupsFor( + CarrierType.USPS, + listOf(it.flatBoxes, it.boxes, it.expressBoxes, it.envelopes) + ) + }, + dhl?.let { + groupsFor( + CarrierType.DHL, + listOf(it.domesticAndInternationalPackages) + ) + }, + ups?.let { + groupsFor( + CarrierType.UPS, + listOf(it.domesticAndInternationalPackages) + ) } - } - - return buildMap { - if (uspsPackages.isNotEmpty()) { - this[CarrierType.USPS] = CarrierDAO(uspsPackages) - } - if (dhlPackages.isNotEmpty()) { - this[CarrierType.DHL] = CarrierDAO(dhlPackages) - } - if (upsPackages.isNotEmpty()) { - this[CarrierType.UPS] = CarrierDAO(upsPackages) - } - } + ) } private fun CarrierPackageGroupDTO.toCarrierGroup( storeOptions: PackageStoreOptionsDTO?, savedCarrierPackages: List? - ) = CarrierPackageGroupDAO( + ) = CarrierPackageGroup( description = title.orEmpty(), packages = definitions?.map { - PackageDAO( + Package( id = it.id.orEmpty(), name = it.name.orEmpty(), dimensions = it.outerDimensions.orEmpty(), @@ -142,7 +146,7 @@ class WooShippingLabelPackageMapper @Inject constructor() { } ?: emptyList() ) - private fun mapStoreOptions(optionsDTO: PackageStoreOptionsDTO) = StoreOptionsDAO( + private fun mapStoreOptions(optionsDTO: PackageStoreOptionsDTO) = StoreOptions( currencySymbol = optionsDTO.currencySymbol.orEmpty(), dimensionUnit = optionsDTO.dimensionUnit.orEmpty(), weightUnit = optionsDTO.weightUnit.orEmpty(), diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/WooShippingLabelPackageRepository.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/WooShippingLabelPackageRepository.kt index 8c0b79f5a9de..7bead0b9e44d 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/WooShippingLabelPackageRepository.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/WooShippingLabelPackageRepository.kt @@ -4,7 +4,8 @@ import com.woocommerce.android.tools.SelectedSite import com.woocommerce.android.ui.orders.wooshippinglabels.packages.networking.CustomPackageCreationRequestData import com.woocommerce.android.ui.orders.wooshippinglabels.packages.networking.WooShippingLabelPackageRestClient import org.wordpress.android.fluxc.model.SiteModel -import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooResult +import org.wordpress.android.fluxc.persistence.dao.WooShippingDao +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity import javax.inject.Inject import javax.inject.Singleton @@ -12,51 +13,111 @@ import javax.inject.Singleton class WooShippingLabelPackageRepository @Inject constructor( private val selectedSite: SelectedSite, private val packageMapper: WooShippingLabelPackageMapper, - private val packageRestClient: WooShippingLabelPackageRestClient + private val packageRestClient: WooShippingLabelPackageRestClient, + private val wooShippingDao: WooShippingDao ) { - suspend fun fetchAllStorePackages( + suspend fun fetchShippingPackages( site: SiteModel = selectedSite.get() - ) = with(packageRestClient.fetchShippingLabelPackages(site)) { - result.takeIf { isError.not() } - ?.let { packageMapper(it) } - ?.let { WooResult(it) } - ?: WooResult(error) - } + ) = packageRestClient.fetchShippingLabelPackages(site) + .asWooResult { packageMapper(site = selectedSite.get(), response = it) } + .also { result -> + result.model?.takeIf { !result.isError }?.let { model -> wooShippingDao.insertShippingPackages(model) } + } + + fun observeShippingPackages( + site: SiteModel = selectedSite.get() + ) = wooShippingDao.observeShippingPackages(site.localId()) suspend fun createCustomPackage( requestData: List, site: SiteModel = selectedSite.get(), - ) = with(packageRestClient.postNewCustomPackage(site, requestData)) { - result.takeIf { isError.not() } - ?.let { packageMapper(it) } - ?.let { WooResult(it) } - ?: WooResult(error) - } + ) = packageRestClient.postNewCustomPackage(site, requestData) + .asWooResult { packageMapper(site = selectedSite.get(), response = it) } + .also { result -> + result.model?.takeIf { !result.isError }?.let { model -> + val cachedPackages = wooShippingDao.getShippingPackages(site.localId()) ?: return@also + wooShippingDao.insertShippingPackages(cachedPackages.copy(savedPackages = model)) + } + } suspend fun saveCarrierPackage( savedPackageId: String, parentCarrierId: String, site: SiteModel, - ) = with( - packageRestClient.postPredefinedPackages( - site, - mapOf(parentCarrierId to listOf(savedPackageId)) - ) - ) { - result.takeIf { isError.not() } - ?.let { packageMapper(it) } - ?.let { WooResult(it) } - ?: WooResult(error) - } + ) = packageRestClient.postPredefinedPackages(site, requestData = mapOf(parentCarrierId to listOf(savedPackageId))) + .asWooResult { packageMapper(selectedSite.get(), response = it) } + .also { result -> + val cachedPackages = wooShippingDao.getShippingPackages(site.localId()) ?: return@also + cachedPackages.markPackageSaved(parentCarrierId, savedPackageId) + ?.let { wooShippingDao.insertShippingPackages(it) } + } suspend fun deleteSavedCarrierPackage( packageId: String, isUserDefined: Boolean, site: SiteModel, - ) = with(packageRestClient.deleteSavedCarrierPackage(site, isUserDefined, packageId)) { - result.takeIf { isError.not() } - ?.let { packageMapper(it) } - ?.let { WooResult(it) } - ?: WooResult(error) + ) = packageRestClient.deleteSavedCarrierPackage(site, isUserDefined, packageId) + .asWooResult { packageMapper(site = selectedSite.get(), response = it) } + .also { + val cachedPackages = wooShippingDao.getShippingPackages(site.localId()) ?: return@also + cachedPackages.markPackageRemoved(packageId, isUserDefined) + ?.let { wooShippingDao.insertShippingPackages(it) } + } + + private fun WooShippingPackagesEntity.markPackageSaved( + parentCarrierId: String, + packageId: String + ): WooShippingPackagesEntity? { + var targetPackage: WooShippingPackagesEntity.Package? = null + + val updatedCarrierGroups = carrierPackageGroups.map { carrierGroup -> + if (carrierGroup.carrierType?.id == parentCarrierId) { + carrierGroup.copy( + packageGroups = carrierGroup.packageGroups?.map { packageGroup -> + packageGroup.copy( + packages = packageGroup.packages?.map { p -> + if (p.id == packageId) { + p.copy(saved = true).also { targetPackage = it } + } else { + p + } + } + ) + } + ) + } else { + carrierGroup + } + } + + targetPackage ?: return this + + val updatedSavedPackages = if (savedPackages.any { it.id == packageId }) { + savedPackages + } else { + savedPackages + targetPackage + } + return copy(carrierPackageGroups = updatedCarrierGroups, savedPackages = updatedSavedPackages) + } + + private fun WooShippingPackagesEntity.markPackageRemoved( + packageId: String, + isUserDefined: Boolean + ): WooShippingPackagesEntity? { + val updatedCarrierGroups = carrierPackageGroups.map { carrierGroup -> + carrierGroup.copy( + packageGroups = carrierGroup.packageGroups?.map { packageGroup -> + packageGroup.copy( + packages = packageGroup.packages?.map { p -> + if (p.id == packageId && p.isUserDefined == isUserDefined) p.copy(saved = false) else p + } + ) + } + ) + } + + val updatedSavedPackages = savedPackages.filterNot { it.id == packageId } + + return copy(carrierPackageGroups = updatedCarrierGroups, savedPackages = updatedSavedPackages) } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/ui/UIModels.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/ui/UIModels.kt index 76090ae05450..5c67dec5a40e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/ui/UIModels.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/ui/UIModels.kt @@ -4,10 +4,10 @@ import android.os.Parcelable import com.woocommerce.android.R import com.woocommerce.android.extensions.isNotNullOrEmpty import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.PackageType -import com.woocommerce.android.ui.orders.wooshippinglabels.packages.datasource.CarrierType -import com.woocommerce.android.ui.orders.wooshippinglabels.packages.datasource.PackageDAO import kotlinx.parcelize.IgnoredOnParcel import kotlinx.parcelize.Parcelize +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity.CarrierType +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity.Package @Parcelize data class PackageData( @@ -68,18 +68,18 @@ data class PackageData( */ const val DEFAULT_HEIGHT = 5.0 - fun fromPackageDAO(dao: PackageDAO, isSelected: Boolean = false) = PackageData( - id = dao.id, - name = dao.name, - dimensions = dao.dimensions, - weight = dao.weight, + fun fromPackageEntity(entity: Package, isSelected: Boolean = false) = PackageData( + id = entity.id ?: EMPTY.id, + name = entity.name ?: EMPTY.name, + dimensions = entity.dimensions ?: EMPTY.dimensions, + weight = entity.weight ?: EMPTY.weight, isSelected = isSelected, - isUserDefined = dao.isUserDefined, - isLetter = dao.isLetter, - dimensionUnit = dao.dimensionUnit, - weightUnit = dao.weightUnit, - groupName = dao.groupName, - isStarred = dao.saved + isUserDefined = entity.isUserDefined, + isLetter = entity.isLetter, + dimensionUnit = entity.dimensionUnit ?: EMPTY.dimensionUnit, + weightUnit = entity.weightUnit ?: EMPTY.weightUnit, + groupName = entity.groupName, + isStarred = entity.saved ) } } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/WooShippingLabelPackageCreationViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/WooShippingLabelPackageCreationViewModelTest.kt index 801ff24b2443..e227ac16c81a 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/WooShippingLabelPackageCreationViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/WooShippingLabelPackageCreationViewModelTest.kt @@ -14,8 +14,7 @@ import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingL import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.PackagesState.Data import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.ShowPackageTypeDialog import com.woocommerce.android.ui.orders.wooshippinglabels.packages.WooShippingLabelPackageCreationViewModel.ViewState -import com.woocommerce.android.ui.orders.wooshippinglabels.packages.datasource.FetchPackagesFromStore -import com.woocommerce.android.ui.orders.wooshippinglabels.packages.datasource.PackageDAO +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.datasource.ObserveShippingPackages import com.woocommerce.android.ui.orders.wooshippinglabels.packages.datasource.WooShippingLabelPackageRepository import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.Carrier import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.Carrier.DHL @@ -28,6 +27,7 @@ import com.woocommerce.android.viewmodel.BaseUnitTest import com.woocommerce.android.viewmodel.MultiLiveEvent.Event import com.woocommerce.android.viewmodel.ResourceProvider import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.advanceUntilIdle import org.assertj.core.api.Assertions.assertThat import org.junit.Before @@ -44,13 +44,14 @@ import org.wordpress.android.fluxc.network.BaseRequest.GenericErrorType import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooError import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooErrorType import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooResult +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity @OptIn(ExperimentalCoroutinesApi::class) class WooShippingLabelPackageCreationViewModelTest : BaseUnitTest() { private lateinit var sut: WooShippingLabelPackageCreationViewModel private val resourceProvider: ResourceProvider = mock() - private val fetchPackages: FetchPackagesFromStore = mock() + private val observeShippingPackages: ObserveShippingPackages = mock() private val packageRepository: WooShippingLabelPackageRepository = mock() private val selectedSite: SelectedSite = mock { on { getOrNull() } doReturn SiteModel().apply { siteId = 123 } @@ -80,7 +81,8 @@ class WooShippingLabelPackageCreationViewModelTest : BaseUnitTest() { savedState, selectedSite, resourceProvider, - fetchPackages, + observeShippingPackages, + mock(), updateSavedCarrierPackages, packageRepository, tracker @@ -174,7 +176,7 @@ class WooShippingLabelPackageCreationViewModelTest : BaseUnitTest() { whenever(packageRepository.createCustomPackage(any(), any())).thenReturn( WooResult( listOf( - PackageDAO( + WooShippingPackagesEntity.Package( id = "1", name = "Saved Package 1", dimensions = "dimensions", @@ -302,11 +304,13 @@ class WooShippingLabelPackageCreationViewModelTest : BaseUnitTest() { isSelected = false, isLetter = true, ) - whenever(fetchPackages()).thenReturn( - Data( - storeOptions = StoreOptionsForPackages.DEFAULT, - carrierPackages = emptyMap(), - savedPackages = listOf(package1, package2) + whenever(observeShippingPackages()).thenReturn( + flowOf( + Data( + storeOptions = StoreOptionsForPackages.DEFAULT, + carrierPackages = emptyMap(), + savedPackages = listOf(package1, package2) + ) ) ) @@ -314,7 +318,8 @@ class WooShippingLabelPackageCreationViewModelTest : BaseUnitTest() { savedState, selectedSite, resourceProvider, - fetchPackages, + observeShippingPackages, + mock(), updateSavedCarrierPackages, packageRepository, tracker @@ -356,11 +361,13 @@ class WooShippingLabelPackageCreationViewModelTest : BaseUnitTest() { ) ) ) - whenever(fetchPackages()).thenReturn( - Data( - storeOptions = StoreOptionsForPackages.DEFAULT, - carrierPackages = carrierPackages, - savedPackages = emptyList() + whenever(observeShippingPackages()).thenReturn( + flowOf( + Data( + storeOptions = StoreOptionsForPackages.DEFAULT, + carrierPackages = carrierPackages, + savedPackages = emptyList() + ) ) ) @@ -368,7 +375,8 @@ class WooShippingLabelPackageCreationViewModelTest : BaseUnitTest() { savedState, selectedSite, resourceProvider, - fetchPackages, + observeShippingPackages, + mock(), updateSavedCarrierPackages, packageRepository, tracker @@ -441,11 +449,13 @@ class WooShippingLabelPackageCreationViewModelTest : BaseUnitTest() { ) ) ) - whenever(fetchPackages()).thenReturn( - Data( - storeOptions = StoreOptionsForPackages.DEFAULT, - carrierPackages = carrierPackages, - savedPackages = emptyList() + whenever(observeShippingPackages()).thenReturn( + flowOf( + Data( + storeOptions = StoreOptionsForPackages.DEFAULT, + carrierPackages = carrierPackages, + savedPackages = emptyList() + ) ) ) @@ -453,7 +463,8 @@ class WooShippingLabelPackageCreationViewModelTest : BaseUnitTest() { savedState, selectedSite, resourceProvider, - fetchPackages, + observeShippingPackages, + mock(), updateSavedCarrierPackages, packageRepository, tracker @@ -498,11 +509,13 @@ class WooShippingLabelPackageCreationViewModelTest : BaseUnitTest() { ) ) ) - whenever(fetchPackages()).thenReturn( - Data( - storeOptions = StoreOptionsForPackages.DEFAULT, - carrierPackages = initialCarrierPackages, - savedPackages = emptyList() + whenever(observeShippingPackages()).thenReturn( + flowOf( + Data( + storeOptions = StoreOptionsForPackages.DEFAULT, + carrierPackages = initialCarrierPackages, + savedPackages = emptyList() + ) ) ) @@ -510,7 +523,8 @@ class WooShippingLabelPackageCreationViewModelTest : BaseUnitTest() { savedState, selectedSite, resourceProvider, - fetchPackages, + observeShippingPackages, + mock(), updateSavedCarrierPackages, packageRepository, tracker @@ -560,11 +574,13 @@ class WooShippingLabelPackageCreationViewModelTest : BaseUnitTest() { ) val initialSavedPackages = emptyList() - whenever(fetchPackages()).thenReturn( - Data( - storeOptions = StoreOptionsForPackages.DEFAULT, - carrierPackages = initialCarrierPackages, - savedPackages = initialSavedPackages + whenever(observeShippingPackages()).thenReturn( + flowOf( + Data( + storeOptions = StoreOptionsForPackages.DEFAULT, + carrierPackages = initialCarrierPackages, + savedPackages = initialSavedPackages + ) ) ) @@ -572,7 +588,8 @@ class WooShippingLabelPackageCreationViewModelTest : BaseUnitTest() { savedState, selectedSite, resourceProvider, - fetchPackages, + observeShippingPackages, + mock(), updateSavedCarrierPackages, packageRepository, tracker @@ -609,11 +626,13 @@ class WooShippingLabelPackageCreationViewModelTest : BaseUnitTest() { ) val initialSavedPackages = listOf(packageToUnstar) - whenever(fetchPackages()).thenReturn( - Data( - storeOptions = StoreOptionsForPackages.DEFAULT, - carrierPackages = initialCarrierPackages, - savedPackages = initialSavedPackages + whenever(observeShippingPackages()).thenReturn( + flowOf( + Data( + storeOptions = StoreOptionsForPackages.DEFAULT, + carrierPackages = initialCarrierPackages, + savedPackages = initialSavedPackages + ) ) ) @@ -621,7 +640,8 @@ class WooShippingLabelPackageCreationViewModelTest : BaseUnitTest() { savedState, selectedSite, resourceProvider, - fetchPackages, + observeShippingPackages, + mock(), updateSavedCarrierPackages, packageRepository, tracker @@ -657,11 +677,13 @@ class WooShippingLabelPackageCreationViewModelTest : BaseUnitTest() { ) val initialSavedPackages = listOf(packageToUnstar) - whenever(fetchPackages()).thenReturn( - Data( - storeOptions = StoreOptionsForPackages.DEFAULT, - carrierPackages = initialCarrierPackages, - savedPackages = initialSavedPackages + whenever(observeShippingPackages()).thenReturn( + flowOf( + Data( + storeOptions = StoreOptionsForPackages.DEFAULT, + carrierPackages = initialCarrierPackages, + savedPackages = initialSavedPackages + ) ) ) val wooError = WooError(type = WooErrorType.API_ERROR, original = GenericErrorType.UNKNOWN) @@ -672,7 +694,8 @@ class WooShippingLabelPackageCreationViewModelTest : BaseUnitTest() { savedState, selectedSite, resourceProvider, - fetchPackages, + observeShippingPackages, + mock(), updateSavedCarrierPackages, packageRepository, tracker @@ -705,11 +728,13 @@ class WooShippingLabelPackageCreationViewModelTest : BaseUnitTest() { ) val initialSavedPackages = listOf(packageToRemove) - whenever(fetchPackages()).thenReturn( - Data( - storeOptions = StoreOptionsForPackages.DEFAULT, - carrierPackages = initialCarrierPackages, - savedPackages = initialSavedPackages + whenever(observeShippingPackages()).thenReturn( + flowOf( + Data( + storeOptions = StoreOptionsForPackages.DEFAULT, + carrierPackages = initialCarrierPackages, + savedPackages = initialSavedPackages + ) ) ) @@ -717,7 +742,8 @@ class WooShippingLabelPackageCreationViewModelTest : BaseUnitTest() { savedState, selectedSite, resourceProvider, - fetchPackages, + observeShippingPackages, + mock(), updateSavedCarrierPackages, packageRepository, tracker diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/FetchPackagesFromStoreTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/ObserveShippingPackagesTest.kt similarity index 60% rename from WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/FetchPackagesFromStoreTest.kt rename to WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/ObserveShippingPackagesTest.kt index 89772106ccd3..cb2959a39a13 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/FetchPackagesFromStoreTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/ObserveShippingPackagesTest.kt @@ -6,32 +6,39 @@ import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.Carrier import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.CarrierPackageGroup import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.PackageData import com.woocommerce.android.viewmodel.BaseUnitTest +import junit.framework.TestCase.assertTrue import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.toList import org.assertj.core.api.Assertions.assertThat import org.junit.Test import org.mockito.kotlin.mock import org.mockito.kotlin.whenever +import org.wordpress.android.fluxc.model.LocalOrRemoteId import org.wordpress.android.fluxc.model.SiteModel -import org.wordpress.android.fluxc.network.BaseRequest -import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooError -import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooErrorType -import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooResult +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity @OptIn(ExperimentalCoroutinesApi::class) -class FetchPackagesFromStoreTest : BaseUnitTest() { +class ObserveShippingPackagesTest : BaseUnitTest() { private val packageRepository: WooShippingLabelPackageRepository = mock() + private val fetchShippingPackages: FetchShippingPackages = mock() private val selectedSite: SelectedSite = mock() - private val fetchPackagesFromStore = FetchPackagesFromStore(selectedSite, packageRepository) + private val observeShippingPackages = ObserveShippingPackages( + selectedSite, + packageRepository, + fetchShippingPackages + ) @Test - fun `invoke should return Data with carrier and saved packages`() = testBlocking { - val storePackages = generatePackagesData() + fun `when invoke, then return Data with carrier and saved packages`() = testBlocking { + val shippingPackages = generatePackagesData() val site = SiteModel().apply { id = 1 } whenever(selectedSite.get()).thenReturn(site) - whenever(packageRepository.fetchAllStorePackages(site)).thenReturn(WooResult(storePackages)) + whenever(packageRepository.observeShippingPackages(site)).thenReturn(flowOf(shippingPackages)) - val result = fetchPackagesFromStore() as PackagesState.Data + val result = observeShippingPackages().first() as PackagesState.Data assertThat(result.savedPackages).containsExactly( PackageData( @@ -71,26 +78,41 @@ class FetchPackagesFromStoreTest : BaseUnitTest() { } @Test - fun `invoke should return Error when fetchAllStorePackages returns error`() = testBlocking { - val error = WooError(WooErrorType.GENERIC_ERROR, BaseRequest.GenericErrorType.UNKNOWN) + fun `when fetchAllStorePackages returns error and no cache, then return Error`() = testBlocking { + val error = Exception("error") + val site = SiteModel().apply { id = 1 } + whenever(selectedSite.get()).thenReturn(site) + whenever(packageRepository.observeShippingPackages(site)).thenReturn(flowOf(null)) + whenever(fetchShippingPackages()).thenReturn(Result.failure(error)) + + val result = observeShippingPackages().first() + + assertThat(result).isEqualTo(PackagesState.Error(error.message!!)) + } + + @Test + fun `when starting, then refresh data once`() = testBlocking { val site = SiteModel().apply { id = 1 } + val shippingPackages = generatePackagesData() whenever(selectedSite.get()).thenReturn(site) - whenever(packageRepository.fetchAllStorePackages(site)).thenReturn(WooResult(error)) + whenever(packageRepository.observeShippingPackages(site)).thenReturn(flowOf(shippingPackages)) + whenever(fetchShippingPackages()).thenReturn(Result.success(shippingPackages)) - val result = fetchPackagesFromStore() + val result = observeShippingPackages().toList() - assertThat(result).isEqualTo(PackagesState.Error(WooErrorType.GENERIC_ERROR.name)) + assertTrue(result.size == 1) } - private fun generatePackagesData() = StorePackagesDAO( - storeOptions = StoreOptionsDAO( + private fun generatePackagesData() = WooShippingPackagesEntity( + localSiteId = LocalOrRemoteId.LocalId(1), + storeOptions = WooShippingPackagesEntity.StoreOptions( currencySymbol = "$", dimensionUnit = "cm", weightUnit = "kg", originCountry = "US" ), savedPackages = listOf( - PackageDAO( + WooShippingPackagesEntity.Package( id = "1", name = "Saved Package 1", dimensions = "dimensions", @@ -100,7 +122,7 @@ class FetchPackagesFromStoreTest : BaseUnitTest() { weightUnit = "kg", saved = true ), - PackageDAO( + WooShippingPackagesEntity.Package( id = "2", name = "Saved Package 2", dimensions = "dimensions", @@ -111,13 +133,14 @@ class FetchPackagesFromStoreTest : BaseUnitTest() { saved = true ) ), - carrierPackages = mapOf( - CarrierType.USPS to CarrierDAO( - packageGroup = listOf( - CarrierPackageGroupDAO( + carrierPackageGroups = listOf( + WooShippingPackagesEntity.CarrierPackageGroups( + carrierType = WooShippingPackagesEntity.CarrierType.USPS, + packageGroups = listOf( + WooShippingPackagesEntity.CarrierPackageGroup( description = "Group 1", packages = listOf( - PackageDAO( + WooShippingPackagesEntity.Package( id = "1", name = "Carrier Package 1", dimensions = "dimensions", diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/WooShippingLabelPackageRepositoryTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/WooShippingLabelPackageRepositoryTest.kt index f8ddc4e89732..50689ca3543b 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/WooShippingLabelPackageRepositoryTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/packages/datasource/WooShippingLabelPackageRepositoryTest.kt @@ -1,6 +1,7 @@ package com.woocommerce.android.ui.orders.wooshippinglabels.packages.datasource import com.woocommerce.android.tools.SelectedSite +import com.woocommerce.android.ui.orders.wooshippinglabels.packages.networking.PackageCreationResponse import com.woocommerce.android.ui.orders.wooshippinglabels.packages.networking.PackageResponse import com.woocommerce.android.ui.orders.wooshippinglabels.packages.networking.WooShippingLabelPackageRestClient import com.woocommerce.android.viewmodel.BaseUnitTest @@ -8,13 +9,24 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import org.assertj.core.api.Assertions.assertThat import org.junit.Before import org.junit.Test +import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.eq import org.mockito.kotlin.mock +import org.mockito.kotlin.verify import org.mockito.kotlin.whenever +import org.wordpress.android.fluxc.model.LocalOrRemoteId import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.network.BaseRequest.GenericErrorType.UNKNOWN import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooError import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooErrorType.GENERIC_ERROR import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooPayload +import org.wordpress.android.fluxc.persistence.dao.WooShippingDao +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity.CarrierPackageGroup +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity.CarrierPackageGroups +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity.CarrierType +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity.Package @OptIn(ExperimentalCoroutinesApi::class) class WooShippingLabelPackageRepositoryTest : BaseUnitTest() { @@ -23,47 +35,163 @@ class WooShippingLabelPackageRepositoryTest : BaseUnitTest() { private val selectedSite: SelectedSite = mock() private val packageMapper: WooShippingLabelPackageMapper = mock() private val packageRestClient: WooShippingLabelPackageRestClient = mock() - private val siteModel: SiteModel = mock() + private val wooShippingDao: WooShippingDao = mock() + private val siteModel: SiteModel = SiteModel().apply { id = 1 } @Before fun setUp() { whenever(selectedSite.get()).thenReturn(siteModel) - repository = WooShippingLabelPackageRepository(selectedSite, packageMapper, packageRestClient) + repository = WooShippingLabelPackageRepository(selectedSite, packageMapper, packageRestClient, wooShippingDao) } @Test - fun `fetchAllStorePackages returns WooResult with result`() = testBlocking { - val storePackagesDAO = StorePackagesDAO( - storeOptions = StoreOptionsDAO( + fun `when fetchShippingPackages succeed, then return WooResult with result`() = testBlocking { + val localSiteId = LocalOrRemoteId.LocalId(1) + val shippingPackages = WooShippingPackagesEntity( + localSiteId = localSiteId, + storeOptions = WooShippingPackagesEntity.StoreOptions( currencySymbol = "", dimensionUnit = "", weightUnit = "", originCountry = "" ), savedPackages = listOf(), - carrierPackages = mapOf() + carrierPackageGroups = listOf() ) val packageResponse = mock() whenever(packageRestClient.fetchShippingLabelPackages(siteModel)).thenReturn(WooPayload(packageResponse)) - whenever(packageMapper(packageResponse)).thenReturn(storePackagesDAO) + whenever(packageMapper(siteModel, packageResponse)).thenReturn(shippingPackages) - val result = repository.fetchAllStorePackages() + val result = repository.fetchShippingPackages() assertThat(result.isError).isFalse - assertThat(storePackagesDAO).isEqualTo(result.model) + assertThat(shippingPackages).isEqualTo(result.model) } @Test - fun `fetchAllStorePackages returns WooResult with error`() = testBlocking { - val error = WooError( - type = GENERIC_ERROR, - original = UNKNOWN - ) + fun `when fetchShippingPackages returns error, then return WooResult with error`() = testBlocking { + val error = WooError(type = GENERIC_ERROR, original = UNKNOWN) whenever(packageRestClient.fetchShippingLabelPackages(siteModel)).thenReturn(WooPayload(error)) - val result = repository.fetchAllStorePackages() + val result = repository.fetchShippingPackages() assertThat(result.isError).isTrue assertThat(error).isEqualTo(result.error) } + + @Test + fun `when saveCarrierPackage invoke, then mark package saved in cache and add to savedPackages`() = testBlocking { + // Given + val localSiteId = LocalOrRemoteId.LocalId(1) + val packageId = "p1" + val parentCarrierId = CarrierType.USPS.id + val initialPackage = Package( + id = packageId, + name = "Carrier Package 1", + dimensions = "", + weight = "", + isLetter = false, + dimensionUnit = "", + isUserDefined = false, + weightUnit = "", + groupName = "Group 1", + saved = false + ) + val initialEntity = WooShippingPackagesEntity( + localSiteId = localSiteId, + storeOptions = WooShippingPackagesEntity.StoreOptions("$", "cm", "kg", "US"), + savedPackages = emptyList(), + carrierPackageGroups = listOf( + CarrierPackageGroups( + carrierType = CarrierType.USPS, + packageGroups = listOf( + CarrierPackageGroup( + description = "Group 1", + packages = listOf(initialPackage) + ) + ) + ) + ) + ) + whenever(wooShippingDao.getShippingPackages(localSiteId)).thenReturn(initialEntity) + whenever(packageRestClient.postPredefinedPackages(eq(siteModel), any())).thenReturn( + WooPayload( + PackageCreationResponse() + ) + ) + + // When + repository.saveCarrierPackage(savedPackageId = packageId, parentCarrierId = parentCarrierId, site = siteModel) + + // Then + val captor = argumentCaptor() + verify(wooShippingDao).insertShippingPackages(captor.capture()) + val updated = captor.firstValue + + // Assert saved flag in carrier groups + val updatedPackage = updated.carrierPackageGroups + .first { it.carrierType == CarrierType.USPS } + .packageGroups!!.first().packages!!.first { it.id == packageId } + assertThat(updatedPackage.saved).isTrue + + // Assert savedPackages contains the package once + assertThat(updated.savedPackages.map { it.id }).containsExactly(packageId) + } + + @Test + fun `when deleteSavedCarrierPackage invoke, then mark package unsaved in cache and remove from savedPackages`() = + testBlocking { + // Given + val localSiteId = LocalOrRemoteId.LocalId(1) + val packageId = "p1" + val isUserDefined = false + val initialPackage = Package( + id = packageId, + name = "Carrier Package 1", + dimensions = "", + weight = "", + isLetter = false, + dimensionUnit = "", + isUserDefined = isUserDefined, + weightUnit = "", + groupName = "Group 1", + saved = true + ) + val initialEntity = WooShippingPackagesEntity( + localSiteId = localSiteId, + storeOptions = WooShippingPackagesEntity.StoreOptions("$", "cm", "kg", "US"), + savedPackages = listOf(initialPackage), + carrierPackageGroups = listOf( + CarrierPackageGroups( + carrierType = CarrierType.USPS, + packageGroups = listOf( + CarrierPackageGroup( + description = "Group 1", + packages = listOf(initialPackage) + ) + ) + ) + ) + ) + whenever(wooShippingDao.getShippingPackages(localSiteId)).thenReturn(initialEntity) + whenever(packageRestClient.deleteSavedCarrierPackage(eq(siteModel), eq(isUserDefined), eq(packageId))) + .thenReturn(WooPayload(PackageCreationResponse())) + + // When + repository.deleteSavedCarrierPackage(packageId = packageId, isUserDefined = isUserDefined, site = siteModel) + + // Then + val captor = argumentCaptor() + verify(wooShippingDao).insertShippingPackages(captor.capture()) + val updated = captor.firstValue + + // Assert saved flag in carrier groups is false + val updatedPackage = updated.carrierPackageGroups + .first { it.carrierType == CarrierType.USPS } + .packageGroups!!.first().packages!!.first { it.id == packageId } + assertThat(updatedPackage.saved).isFalse + + // Assert savedPackages no longer contains the package + assertThat(updated.savedPackages.any { it.id == packageId }).isFalse + } } diff --git a/libs/fluxc-plugin/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/60.json b/libs/fluxc-plugin/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/60.json index 4c39b1f027e6..1529162947de 100644 --- a/libs/fluxc-plugin/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/60.json +++ b/libs/fluxc-plugin/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/60.json @@ -3847,4 +3847,4 @@ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'c8e33b8197848f2e327651207f15e6b6')" ] } -} \ No newline at end of file +} diff --git a/libs/fluxc-plugin/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/63.json b/libs/fluxc-plugin/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/63.json index 2c0150529523..753ff62ae9d7 100644 --- a/libs/fluxc-plugin/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/63.json +++ b/libs/fluxc-plugin/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/63.json @@ -3856,4 +3856,4 @@ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '7c4f4ec2c824fb53fb671f268430484f')" ] } -} \ No newline at end of file +} diff --git a/libs/fluxc-plugin/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/64.json b/libs/fluxc-plugin/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/64.json new file mode 100644 index 000000000000..3c626f298bc9 --- /dev/null +++ b/libs/fluxc-plugin/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/64.json @@ -0,0 +1,3895 @@ +{ + "formatVersion": 1, + "database": { + "version": 64, + "identityHash": "c10399e20f850a169d96cac1e3b92dfd", + "entities": [ + { + "tableName": "AddonEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`addonLocalId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `globalGroupLocalId` INTEGER, `productRemoteId` INTEGER, `localSiteId` INTEGER, `type` TEXT NOT NULL, `display` TEXT, `name` TEXT NOT NULL, `titleFormat` TEXT NOT NULL, `description` TEXT, `required` INTEGER NOT NULL, `position` INTEGER NOT NULL, `restrictions` TEXT, `priceType` TEXT, `price` TEXT, `min` INTEGER, `max` INTEGER, FOREIGN KEY(`globalGroupLocalId`) REFERENCES `GlobalAddonGroupEntity`(`globalGroupLocalId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "addonLocalId", + "columnName": "addonLocalId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "globalGroupLocalId", + "columnName": "globalGroupLocalId", + "affinity": "INTEGER" + }, + { + "fieldPath": "productRemoteId", + "columnName": "productRemoteId", + "affinity": "INTEGER" + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER" + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "display", + "columnName": "display", + "affinity": "TEXT" + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "titleFormat", + "columnName": "titleFormat", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT" + }, + { + "fieldPath": "required", + "columnName": "required", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "position", + "columnName": "position", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "restrictions", + "columnName": "restrictions", + "affinity": "TEXT" + }, + { + "fieldPath": "priceType", + "columnName": "priceType", + "affinity": "TEXT" + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "TEXT" + }, + { + "fieldPath": "min", + "columnName": "min", + "affinity": "INTEGER" + }, + { + "fieldPath": "max", + "columnName": "max", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "addonLocalId" + ] + }, + "indices": [ + { + "name": "index_AddonEntity_globalGroupLocalId", + "unique": false, + "columnNames": [ + "globalGroupLocalId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_AddonEntity_globalGroupLocalId` ON `${TABLE_NAME}` (`globalGroupLocalId`)" + } + ], + "foreignKeys": [ + { + "table": "GlobalAddonGroupEntity", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "globalGroupLocalId" + ], + "referencedColumns": [ + "globalGroupLocalId" + ] + } + ] + }, + { + "tableName": "AddonOptionEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`addonOptionLocalId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `addonLocalId` INTEGER NOT NULL, `priceType` TEXT NOT NULL, `label` TEXT, `price` TEXT, `image` TEXT, FOREIGN KEY(`addonLocalId`) REFERENCES `AddonEntity`(`addonLocalId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "addonOptionLocalId", + "columnName": "addonOptionLocalId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "addonLocalId", + "columnName": "addonLocalId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "priceType", + "columnName": "priceType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "label", + "columnName": "label", + "affinity": "TEXT" + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "TEXT" + }, + { + "fieldPath": "image", + "columnName": "image", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "addonOptionLocalId" + ] + }, + "indices": [ + { + "name": "index_AddonOptionEntity_addonLocalId", + "unique": false, + "columnNames": [ + "addonLocalId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_AddonOptionEntity_addonLocalId` ON `${TABLE_NAME}` (`addonLocalId`)" + } + ], + "foreignKeys": [ + { + "table": "AddonEntity", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "addonLocalId" + ], + "referencedColumns": [ + "addonLocalId" + ] + } + ] + }, + { + "tableName": "Coupons", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `localSiteId` INTEGER NOT NULL, `code` TEXT, `amount` TEXT, `dateCreated` TEXT, `dateCreatedGmt` TEXT, `dateModified` TEXT, `dateModifiedGmt` TEXT, `discountType` TEXT, `description` TEXT, `dateExpires` TEXT, `dateExpiresGmt` TEXT, `usageCount` INTEGER, `isForIndividualUse` INTEGER, `usageLimit` INTEGER, `usageLimitPerUser` INTEGER, `limitUsageToXItems` INTEGER, `isShippingFree` INTEGER, `areSaleItemsExcluded` INTEGER, `minimumAmount` TEXT, `maximumAmount` TEXT, `includedProductIds` TEXT, `excludedProductIds` TEXT, `includedCategoryIds` TEXT, `excludedCategoryIds` TEXT, PRIMARY KEY(`id`, `localSiteId`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "code", + "columnName": "code", + "affinity": "TEXT" + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "TEXT" + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT" + }, + { + "fieldPath": "dateCreatedGmt", + "columnName": "dateCreatedGmt", + "affinity": "TEXT" + }, + { + "fieldPath": "dateModified", + "columnName": "dateModified", + "affinity": "TEXT" + }, + { + "fieldPath": "dateModifiedGmt", + "columnName": "dateModifiedGmt", + "affinity": "TEXT" + }, + { + "fieldPath": "discountType", + "columnName": "discountType", + "affinity": "TEXT" + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT" + }, + { + "fieldPath": "dateExpires", + "columnName": "dateExpires", + "affinity": "TEXT" + }, + { + "fieldPath": "dateExpiresGmt", + "columnName": "dateExpiresGmt", + "affinity": "TEXT" + }, + { + "fieldPath": "usageCount", + "columnName": "usageCount", + "affinity": "INTEGER" + }, + { + "fieldPath": "isForIndividualUse", + "columnName": "isForIndividualUse", + "affinity": "INTEGER" + }, + { + "fieldPath": "usageLimit", + "columnName": "usageLimit", + "affinity": "INTEGER" + }, + { + "fieldPath": "usageLimitPerUser", + "columnName": "usageLimitPerUser", + "affinity": "INTEGER" + }, + { + "fieldPath": "limitUsageToXItems", + "columnName": "limitUsageToXItems", + "affinity": "INTEGER" + }, + { + "fieldPath": "isShippingFree", + "columnName": "isShippingFree", + "affinity": "INTEGER" + }, + { + "fieldPath": "areSaleItemsExcluded", + "columnName": "areSaleItemsExcluded", + "affinity": "INTEGER" + }, + { + "fieldPath": "minimumAmount", + "columnName": "minimumAmount", + "affinity": "TEXT" + }, + { + "fieldPath": "maximumAmount", + "columnName": "maximumAmount", + "affinity": "TEXT" + }, + { + "fieldPath": "includedProductIds", + "columnName": "includedProductIds", + "affinity": "TEXT" + }, + { + "fieldPath": "excludedProductIds", + "columnName": "excludedProductIds", + "affinity": "TEXT" + }, + { + "fieldPath": "includedCategoryIds", + "columnName": "includedCategoryIds", + "affinity": "TEXT" + }, + { + "fieldPath": "excludedCategoryIds", + "columnName": "excludedCategoryIds", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id", + "localSiteId" + ] + } + }, + { + "tableName": "CouponEmails", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`couponId` INTEGER NOT NULL, `localSiteId` INTEGER NOT NULL, `email` TEXT NOT NULL, PRIMARY KEY(`couponId`, `localSiteId`, `email`), FOREIGN KEY(`couponId`, `localSiteId`) REFERENCES `Coupons`(`id`, `localSiteId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "couponId", + "columnName": "couponId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "couponId", + "localSiteId", + "email" + ] + }, + "foreignKeys": [ + { + "table": "Coupons", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "couponId", + "localSiteId" + ], + "referencedColumns": [ + "id", + "localSiteId" + ] + } + ] + }, + { + "tableName": "GlobalAddonGroupEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`globalGroupLocalId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `restrictedCategoriesIds` TEXT NOT NULL, `localSiteId` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "globalGroupLocalId", + "columnName": "globalGroupLocalId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "restrictedCategoriesIds", + "columnName": "restrictedCategoriesIds", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "globalGroupLocalId" + ] + } + }, + { + "tableName": "OrderNotes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `noteId` INTEGER NOT NULL, `orderId` INTEGER NOT NULL, `dateCreated` TEXT, `note` TEXT, `author` TEXT, `isSystemNote` INTEGER NOT NULL, `isCustomerNote` INTEGER NOT NULL, PRIMARY KEY(`localSiteId`, `noteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "noteId", + "columnName": "noteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "orderId", + "columnName": "orderId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT" + }, + { + "fieldPath": "note", + "columnName": "note", + "affinity": "TEXT" + }, + { + "fieldPath": "author", + "columnName": "author", + "affinity": "TEXT" + }, + { + "fieldPath": "isSystemNote", + "columnName": "isSystemNote", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isCustomerNote", + "columnName": "isCustomerNote", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "noteId" + ] + } + }, + { + "tableName": "OrderEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `orderId` INTEGER NOT NULL, `number` TEXT NOT NULL, `status` TEXT NOT NULL, `currency` TEXT NOT NULL, `orderKey` TEXT NOT NULL, `dateCreated` TEXT NOT NULL, `dateModified` TEXT NOT NULL, `total` TEXT NOT NULL, `totalTax` TEXT NOT NULL, `shippingTotal` TEXT NOT NULL, `paymentMethod` TEXT NOT NULL, `paymentMethodTitle` TEXT NOT NULL, `datePaid` TEXT NOT NULL, `pricesIncludeTax` INTEGER NOT NULL, `customerNote` TEXT NOT NULL, `discountTotal` TEXT NOT NULL, `discountCodes` TEXT NOT NULL, `refundTotal` TEXT NOT NULL, `customerId` INTEGER NOT NULL DEFAULT 0, `billingFirstName` TEXT NOT NULL, `billingLastName` TEXT NOT NULL, `billingCompany` TEXT NOT NULL, `billingAddress1` TEXT NOT NULL, `billingAddress2` TEXT NOT NULL, `billingCity` TEXT NOT NULL, `billingState` TEXT NOT NULL, `billingPostcode` TEXT NOT NULL, `billingCountry` TEXT NOT NULL, `billingEmail` TEXT NOT NULL, `billingPhone` TEXT NOT NULL, `shippingFirstName` TEXT NOT NULL, `shippingLastName` TEXT NOT NULL, `shippingCompany` TEXT NOT NULL, `shippingAddress1` TEXT NOT NULL, `shippingAddress2` TEXT NOT NULL, `shippingCity` TEXT NOT NULL, `shippingState` TEXT NOT NULL, `shippingPostcode` TEXT NOT NULL, `shippingCountry` TEXT NOT NULL, `shippingPhone` TEXT NOT NULL, `lineItems` TEXT NOT NULL, `shippingLines` TEXT NOT NULL, `feeLines` TEXT NOT NULL, `taxLines` TEXT NOT NULL, `couponLines` TEXT NOT NULL DEFAULT '', `metaData` TEXT NOT NULL, `paymentUrl` TEXT NOT NULL DEFAULT '', `isEditable` INTEGER NOT NULL DEFAULT 1, `needsPayment` INTEGER, `needsProcessing` INTEGER, `giftCardCode` TEXT NOT NULL DEFAULT '', `giftCardAmount` TEXT NOT NULL DEFAULT '', `shippingTax` TEXT NOT NULL DEFAULT '', `createdVia` TEXT NOT NULL DEFAULT '', PRIMARY KEY(`localSiteId`, `orderId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "orderId", + "columnName": "orderId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "orderKey", + "columnName": "orderKey", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateModified", + "columnName": "dateModified", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "total", + "columnName": "total", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "totalTax", + "columnName": "totalTax", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingTotal", + "columnName": "shippingTotal", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "paymentMethod", + "columnName": "paymentMethod", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "paymentMethodTitle", + "columnName": "paymentMethodTitle", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "datePaid", + "columnName": "datePaid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pricesIncludeTax", + "columnName": "pricesIncludeTax", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "customerNote", + "columnName": "customerNote", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "discountTotal", + "columnName": "discountTotal", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "discountCodes", + "columnName": "discountCodes", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "refundTotal", + "columnName": "refundTotal", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "customerId", + "columnName": "customerId", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "billingFirstName", + "columnName": "billingFirstName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingLastName", + "columnName": "billingLastName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingCompany", + "columnName": "billingCompany", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingAddress1", + "columnName": "billingAddress1", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingAddress2", + "columnName": "billingAddress2", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingCity", + "columnName": "billingCity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingState", + "columnName": "billingState", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingPostcode", + "columnName": "billingPostcode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingCountry", + "columnName": "billingCountry", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingEmail", + "columnName": "billingEmail", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingPhone", + "columnName": "billingPhone", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingFirstName", + "columnName": "shippingFirstName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingLastName", + "columnName": "shippingLastName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingCompany", + "columnName": "shippingCompany", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingAddress1", + "columnName": "shippingAddress1", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingAddress2", + "columnName": "shippingAddress2", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingCity", + "columnName": "shippingCity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingState", + "columnName": "shippingState", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingPostcode", + "columnName": "shippingPostcode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingCountry", + "columnName": "shippingCountry", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingPhone", + "columnName": "shippingPhone", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lineItems", + "columnName": "lineItems", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingLines", + "columnName": "shippingLines", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "feeLines", + "columnName": "feeLines", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "taxLines", + "columnName": "taxLines", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "couponLines", + "columnName": "couponLines", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "metaData", + "columnName": "metaData", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "paymentUrl", + "columnName": "paymentUrl", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "isEditable", + "columnName": "isEditable", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "1" + }, + { + "fieldPath": "needsPayment", + "columnName": "needsPayment", + "affinity": "INTEGER" + }, + { + "fieldPath": "needsProcessing", + "columnName": "needsProcessing", + "affinity": "INTEGER" + }, + { + "fieldPath": "giftCardCode", + "columnName": "giftCardCode", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "giftCardAmount", + "columnName": "giftCardAmount", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "shippingTax", + "columnName": "shippingTax", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "createdVia", + "columnName": "createdVia", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "orderId" + ] + }, + "indices": [ + { + "name": "index_OrderEntity_localSiteId_orderId", + "unique": false, + "columnNames": [ + "localSiteId", + "orderId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_OrderEntity_localSiteId_orderId` ON `${TABLE_NAME}` (`localSiteId`, `orderId`)" + } + ] + }, + { + "tableName": "RefundEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`siteId` INTEGER NOT NULL, `orderId` INTEGER NOT NULL, `refundId` INTEGER NOT NULL, `data` TEXT NOT NULL, PRIMARY KEY(`siteId`, `orderId`, `refundId`))", + "fields": [ + { + "fieldPath": "siteId", + "columnName": "siteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "orderId", + "columnName": "orderId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "refundId", + "columnName": "refundId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "data", + "columnName": "data", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "siteId", + "orderId", + "refundId" + ] + } + }, + { + "tableName": "MetaData", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `parentItemId` INTEGER NOT NULL, `key` TEXT NOT NULL, `value` TEXT NOT NULL, `type` TEXT NOT NULL DEFAULT 'ORDER', PRIMARY KEY(`localSiteId`, `parentItemId`, `id`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "parentItemId", + "columnName": "parentItemId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "'ORDER'" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "parentItemId", + "id" + ] + } + }, + { + "tableName": "InboxNotes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `remoteId` INTEGER NOT NULL, `localSiteId` INTEGER NOT NULL, `name` TEXT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `dateCreated` TEXT NOT NULL, `status` TEXT NOT NULL, `source` TEXT, `type` TEXT, `dateReminder` TEXT)", + "fields": [ + { + "fieldPath": "localId", + "columnName": "localId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "source", + "columnName": "source", + "affinity": "TEXT" + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT" + }, + { + "fieldPath": "dateReminder", + "columnName": "dateReminder", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "localId" + ] + }, + "indices": [ + { + "name": "index_InboxNotes_remoteId_localSiteId", + "unique": true, + "columnNames": [ + "remoteId", + "localSiteId" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_InboxNotes_remoteId_localSiteId` ON `${TABLE_NAME}` (`remoteId`, `localSiteId`)" + } + ] + }, + { + "tableName": "InboxNoteActions", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remoteId` INTEGER NOT NULL, `inboxNoteLocalId` INTEGER NOT NULL, `localSiteId` INTEGER NOT NULL, `name` TEXT NOT NULL, `label` TEXT NOT NULL, `url` TEXT NOT NULL, `query` TEXT, `status` TEXT, `primary` INTEGER NOT NULL, `actionedText` TEXT, PRIMARY KEY(`remoteId`, `inboxNoteLocalId`), FOREIGN KEY(`inboxNoteLocalId`) REFERENCES `InboxNotes`(`localId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "inboxNoteLocalId", + "columnName": "inboxNoteLocalId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "label", + "columnName": "label", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "query", + "columnName": "query", + "affinity": "TEXT" + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT" + }, + { + "fieldPath": "primary", + "columnName": "primary", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "actionedText", + "columnName": "actionedText", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "remoteId", + "inboxNoteLocalId" + ] + }, + "indices": [ + { + "name": "index_InboxNoteActions_inboxNoteLocalId", + "unique": false, + "columnNames": [ + "inboxNoteLocalId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_InboxNoteActions_inboxNoteLocalId` ON `${TABLE_NAME}` (`inboxNoteLocalId`)" + } + ], + "foreignKeys": [ + { + "table": "InboxNotes", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "inboxNoteLocalId" + ], + "referencedColumns": [ + "localId" + ] + } + ] + }, + { + "tableName": "TopPerformerProducts", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `datePeriod` TEXT NOT NULL, `productId` INTEGER NOT NULL, `name` TEXT NOT NULL, `imageUrl` TEXT, `quantity` INTEGER NOT NULL, `currency` TEXT NOT NULL, `total` REAL NOT NULL, `millisSinceLastUpdated` INTEGER NOT NULL, PRIMARY KEY(`datePeriod`, `productId`, `localSiteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "datePeriod", + "columnName": "datePeriod", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "productId", + "columnName": "productId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "imageUrl", + "columnName": "imageUrl", + "affinity": "TEXT" + }, + { + "fieldPath": "quantity", + "columnName": "quantity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "total", + "columnName": "total", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "millisSinceLastUpdated", + "columnName": "millisSinceLastUpdated", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "datePeriod", + "productId", + "localSiteId" + ] + } + }, + { + "tableName": "TaxBasedOnSetting", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `selectedOption` TEXT NOT NULL, PRIMARY KEY(`localSiteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "selectedOption", + "columnName": "selectedOption", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId" + ] + } + }, + { + "tableName": "TaxRate", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `localSiteId` INTEGER NOT NULL, `country` TEXT, `state` TEXT, `postcode` TEXT, `city` TEXT, `rate` TEXT, `name` TEXT, `taxClass` TEXT, PRIMARY KEY(`id`, `localSiteId`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "country", + "columnName": "country", + "affinity": "TEXT" + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT" + }, + { + "fieldPath": "postcode", + "columnName": "postcode", + "affinity": "TEXT" + }, + { + "fieldPath": "city", + "columnName": "city", + "affinity": "TEXT" + }, + { + "fieldPath": "rate", + "columnName": "rate", + "affinity": "TEXT" + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT" + }, + { + "fieldPath": "taxClass", + "columnName": "taxClass", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id", + "localSiteId" + ] + } + }, + { + "tableName": "WooPaymentsDepositsOverview", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `depositsEnabled` INTEGER, `depositsBlocked` INTEGER, `defaultCurrency` TEXT, `delayDays` INTEGER, `weeklyAnchor` TEXT, `monthlyAnchor` INTEGER, `interval` TEXT, PRIMARY KEY(`localSiteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "account.depositsEnabled", + "columnName": "depositsEnabled", + "affinity": "INTEGER" + }, + { + "fieldPath": "account.depositsBlocked", + "columnName": "depositsBlocked", + "affinity": "INTEGER" + }, + { + "fieldPath": "account.defaultCurrency", + "columnName": "defaultCurrency", + "affinity": "TEXT" + }, + { + "fieldPath": "account.depositsSchedule.delayDays", + "columnName": "delayDays", + "affinity": "INTEGER" + }, + { + "fieldPath": "account.depositsSchedule.weeklyAnchor", + "columnName": "weeklyAnchor", + "affinity": "TEXT" + }, + { + "fieldPath": "account.depositsSchedule.monthlyAnchor", + "columnName": "monthlyAnchor", + "affinity": "INTEGER" + }, + { + "fieldPath": "account.depositsSchedule.interval", + "columnName": "interval", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId" + ] + } + }, + { + "tableName": "WooPaymentsDeposits", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `localSiteId` INTEGER NOT NULL, `depositId` TEXT, `date` INTEGER, `type` TEXT, `amount` INTEGER, `status` TEXT, `bankAccount` TEXT, `currency` TEXT, `automatic` INTEGER, `fee` INTEGER, `feePercentage` REAL, `created` INTEGER, `depositType` TEXT NOT NULL, FOREIGN KEY(`localSiteId`) REFERENCES `WooPaymentsDepositsOverview`(`localSiteId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "depositId", + "columnName": "depositId", + "affinity": "TEXT" + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER" + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT" + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "INTEGER" + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT" + }, + { + "fieldPath": "bankAccount", + "columnName": "bankAccount", + "affinity": "TEXT" + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT" + }, + { + "fieldPath": "automatic", + "columnName": "automatic", + "affinity": "INTEGER" + }, + { + "fieldPath": "fee", + "columnName": "fee", + "affinity": "INTEGER" + }, + { + "fieldPath": "feePercentage", + "columnName": "feePercentage", + "affinity": "REAL" + }, + { + "fieldPath": "created", + "columnName": "created", + "affinity": "INTEGER" + }, + { + "fieldPath": "depositType", + "columnName": "depositType", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "foreignKeys": [ + { + "table": "WooPaymentsDepositsOverview", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "localSiteId" + ], + "referencedColumns": [ + "localSiteId" + ] + } + ] + }, + { + "tableName": "WooPaymentsManualDeposits", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `localSiteId` INTEGER NOT NULL, `currency` TEXT, `date` INTEGER, FOREIGN KEY(`localSiteId`) REFERENCES `WooPaymentsDepositsOverview`(`localSiteId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT" + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "foreignKeys": [ + { + "table": "WooPaymentsDepositsOverview", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "localSiteId" + ], + "referencedColumns": [ + "localSiteId" + ] + } + ] + }, + { + "tableName": "WooPaymentsBalance", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `localSiteId` INTEGER NOT NULL, `amount` INTEGER, `currency` TEXT, `fee` INTEGER, `feePercentage` REAL, `net` INTEGER, `balanceType` TEXT NOT NULL, `card` INTEGER, FOREIGN KEY(`localSiteId`) REFERENCES `WooPaymentsDepositsOverview`(`localSiteId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "INTEGER" + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT" + }, + { + "fieldPath": "fee", + "columnName": "fee", + "affinity": "INTEGER" + }, + { + "fieldPath": "feePercentage", + "columnName": "feePercentage", + "affinity": "REAL" + }, + { + "fieldPath": "net", + "columnName": "net", + "affinity": "INTEGER" + }, + { + "fieldPath": "balanceType", + "columnName": "balanceType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sourceTypes.card", + "columnName": "card", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "foreignKeys": [ + { + "table": "WooPaymentsDepositsOverview", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "localSiteId" + ], + "referencedColumns": [ + "localSiteId" + ] + } + ] + }, + { + "tableName": "VisitorSummaryStatsEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `date` TEXT NOT NULL, `granularity` TEXT NOT NULL, `views` INTEGER NOT NULL, `visitors` INTEGER NOT NULL, PRIMARY KEY(`localSiteId`, `date`, `granularity`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "granularity", + "columnName": "granularity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "views", + "columnName": "views", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "visitors", + "columnName": "visitors", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "date", + "granularity" + ] + } + }, + { + "tableName": "ShippingMethod", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `localSiteId` INTEGER NOT NULL, `title` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "id" + ] + } + }, + { + "tableName": "CustomerFromAnalytics", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `userId` INTEGER NOT NULL, `avgOrderValue` REAL NOT NULL, `city` TEXT NOT NULL, `country` TEXT NOT NULL, `dateLastActive` TEXT NOT NULL, `dateLastActiveGmt` TEXT NOT NULL, `dateLastOrder` TEXT NOT NULL, `dateRegistered` TEXT NOT NULL, `dateRegisteredGmt` TEXT NOT NULL, `email` TEXT NOT NULL, `name` TEXT NOT NULL, `ordersCount` INTEGER NOT NULL, `postcode` TEXT NOT NULL, `state` TEXT NOT NULL, `totalSpend` REAL NOT NULL, `username` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `id`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "avgOrderValue", + "columnName": "avgOrderValue", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "city", + "columnName": "city", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "country", + "columnName": "country", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateLastActive", + "columnName": "dateLastActive", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateLastActiveGmt", + "columnName": "dateLastActiveGmt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateLastOrder", + "columnName": "dateLastOrder", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateRegistered", + "columnName": "dateRegistered", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateRegisteredGmt", + "columnName": "dateRegisteredGmt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "ordersCount", + "columnName": "ordersCount", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "postcode", + "columnName": "postcode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "totalSpend", + "columnName": "totalSpend", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "username", + "columnName": "username", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "id" + ] + } + }, + { + "tableName": "ProductEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteId` INTEGER NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, `permalink` TEXT NOT NULL, `dateCreated` TEXT NOT NULL, `dateModified` TEXT NOT NULL, `type` TEXT NOT NULL, `status` TEXT NOT NULL, `featured` INTEGER NOT NULL, `catalogVisibility` TEXT NOT NULL, `description` TEXT NOT NULL, `shortDescription` TEXT NOT NULL, `sku` TEXT NOT NULL, `globalUniqueId` TEXT NOT NULL, `price` TEXT NOT NULL, `regularPrice` TEXT NOT NULL, `salePrice` TEXT NOT NULL, `onSale` INTEGER NOT NULL, `totalSales` INTEGER NOT NULL, `purchasable` INTEGER NOT NULL, `dateOnSaleFrom` TEXT NOT NULL, `dateOnSaleTo` TEXT NOT NULL, `dateOnSaleFromGmt` TEXT NOT NULL, `dateOnSaleToGmt` TEXT NOT NULL, `virtual` INTEGER NOT NULL, `downloadable` INTEGER NOT NULL, `downloadLimit` INTEGER NOT NULL, `downloadExpiry` INTEGER NOT NULL, `soldIndividually` INTEGER NOT NULL, `externalUrl` TEXT NOT NULL, `buttonText` TEXT NOT NULL, `taxStatus` TEXT NOT NULL, `taxClass` TEXT NOT NULL, `manageStock` INTEGER NOT NULL, `stockQuantity` REAL NOT NULL, `stockStatus` TEXT NOT NULL, `backorders` TEXT NOT NULL, `backordersAllowed` INTEGER NOT NULL, `backordered` INTEGER NOT NULL, `shippingRequired` INTEGER NOT NULL, `shippingTaxable` INTEGER NOT NULL, `shippingClass` TEXT NOT NULL, `shippingClassId` INTEGER NOT NULL, `reviewsAllowed` INTEGER NOT NULL, `averageRating` TEXT NOT NULL, `ratingCount` INTEGER NOT NULL, `parentId` INTEGER NOT NULL, `purchaseNote` TEXT NOT NULL, `menuOrder` INTEGER NOT NULL, `categories` TEXT NOT NULL, `tags` TEXT NOT NULL, `images` TEXT NOT NULL, `attributes` TEXT NOT NULL, `variations` TEXT NOT NULL, `downloads` TEXT NOT NULL, `relatedIds` TEXT NOT NULL, `crossSellIds` TEXT NOT NULL, `upsellIds` TEXT NOT NULL, `groupedProductIds` TEXT NOT NULL, `weight` TEXT NOT NULL, `length` TEXT NOT NULL, `width` TEXT NOT NULL, `height` TEXT NOT NULL, `bundledItems` TEXT NOT NULL, `compositeComponents` TEXT NOT NULL, `specialStockStatus` TEXT NOT NULL, `bundleMinSize` REAL, `bundleMaxSize` REAL, `minAllowedQuantity` INTEGER NOT NULL, `maxAllowedQuantity` INTEGER NOT NULL, `groupOfQuantity` INTEGER NOT NULL, `combineVariationQuantities` INTEGER NOT NULL, `password` TEXT, `isSampleProduct` INTEGER NOT NULL, PRIMARY KEY(`localSiteId`, `remoteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "slug", + "columnName": "slug", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "permalink", + "columnName": "permalink", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateModified", + "columnName": "dateModified", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "featured", + "columnName": "featured", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "catalogVisibility", + "columnName": "catalogVisibility", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shortDescription", + "columnName": "shortDescription", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sku", + "columnName": "sku", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "globalUniqueId", + "columnName": "globalUniqueId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "regularPrice", + "columnName": "regularPrice", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "salePrice", + "columnName": "salePrice", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "onSale", + "columnName": "onSale", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "totalSales", + "columnName": "totalSales", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "purchasable", + "columnName": "purchasable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateOnSaleFrom", + "columnName": "dateOnSaleFrom", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateOnSaleTo", + "columnName": "dateOnSaleTo", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateOnSaleFromGmt", + "columnName": "dateOnSaleFromGmt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateOnSaleToGmt", + "columnName": "dateOnSaleToGmt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "virtual", + "columnName": "virtual", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "downloadable", + "columnName": "downloadable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "downloadLimit", + "columnName": "downloadLimit", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "downloadExpiry", + "columnName": "downloadExpiry", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "soldIndividually", + "columnName": "soldIndividually", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "externalUrl", + "columnName": "externalUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "buttonText", + "columnName": "buttonText", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "taxStatus", + "columnName": "taxStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "taxClass", + "columnName": "taxClass", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "manageStock", + "columnName": "manageStock", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "stockQuantity", + "columnName": "stockQuantity", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "stockStatus", + "columnName": "stockStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "backorders", + "columnName": "backorders", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "backordersAllowed", + "columnName": "backordersAllowed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "backordered", + "columnName": "backordered", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shippingRequired", + "columnName": "shippingRequired", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shippingTaxable", + "columnName": "shippingTaxable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shippingClass", + "columnName": "shippingClass", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingClassId", + "columnName": "shippingClassId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "reviewsAllowed", + "columnName": "reviewsAllowed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "averageRating", + "columnName": "averageRating", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "ratingCount", + "columnName": "ratingCount", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "parentId", + "columnName": "parentId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "purchaseNote", + "columnName": "purchaseNote", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "menuOrder", + "columnName": "menuOrder", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "categories", + "columnName": "categories", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "tags", + "columnName": "tags", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "images", + "columnName": "images", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "attributes", + "columnName": "attributes", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "variations", + "columnName": "variations", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "downloads", + "columnName": "downloads", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "relatedIds", + "columnName": "relatedIds", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "crossSellIds", + "columnName": "crossSellIds", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "upsellIds", + "columnName": "upsellIds", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "groupedProductIds", + "columnName": "groupedProductIds", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "weight", + "columnName": "weight", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "length", + "columnName": "length", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "width", + "columnName": "width", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "height", + "columnName": "height", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "bundledItems", + "columnName": "bundledItems", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "compositeComponents", + "columnName": "compositeComponents", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "specialStockStatus", + "columnName": "specialStockStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "bundleMinSize", + "columnName": "bundleMinSize", + "affinity": "REAL" + }, + { + "fieldPath": "bundleMaxSize", + "columnName": "bundleMaxSize", + "affinity": "REAL" + }, + { + "fieldPath": "minAllowedQuantity", + "columnName": "minAllowedQuantity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "maxAllowedQuantity", + "columnName": "maxAllowedQuantity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "groupOfQuantity", + "columnName": "groupOfQuantity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "combineVariationQuantities", + "columnName": "combineVariationQuantities", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "password", + "columnName": "password", + "affinity": "TEXT" + }, + { + "fieldPath": "isSampleProduct", + "columnName": "isSampleProduct", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteId" + ] + } + }, + { + "tableName": "PosProductEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteId` INTEGER NOT NULL, `name` TEXT NOT NULL, `sku` TEXT NOT NULL, `globalUniqueId` TEXT NOT NULL, `type` TEXT NOT NULL, `price` TEXT NOT NULL, `downloadable` INTEGER NOT NULL, `images` TEXT NOT NULL, `attributes` TEXT NOT NULL, `parentId` INTEGER, `status` TEXT NOT NULL, `regularPrice` TEXT NOT NULL, `salePrice` TEXT NOT NULL, `onSale` INTEGER NOT NULL, `description` TEXT NOT NULL, `shortDescription` TEXT NOT NULL, `manageStock` INTEGER NOT NULL, `stockQuantity` REAL, `stockStatus` TEXT NOT NULL, `backordersAllowed` INTEGER NOT NULL, `backordered` INTEGER NOT NULL, `categories` TEXT NOT NULL, `tags` TEXT NOT NULL, `dateModified` TEXT NOT NULL, `variations` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `remoteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sku", + "columnName": "sku", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "globalUniqueId", + "columnName": "globalUniqueId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "downloadable", + "columnName": "downloadable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "images", + "columnName": "images", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "attributes", + "columnName": "attributes", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "parentId", + "columnName": "parentId", + "affinity": "INTEGER" + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "regularPrice", + "columnName": "regularPrice", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "salePrice", + "columnName": "salePrice", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "onSale", + "columnName": "onSale", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shortDescription", + "columnName": "shortDescription", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "manageStock", + "columnName": "manageStock", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "stockQuantity", + "columnName": "stockQuantity", + "affinity": "REAL" + }, + { + "fieldPath": "stockStatus", + "columnName": "stockStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "backordersAllowed", + "columnName": "backordersAllowed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "backordered", + "columnName": "backordered", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "categories", + "columnName": "categories", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "tags", + "columnName": "tags", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateModified", + "columnName": "dateModified", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "variations", + "columnName": "variations", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteId" + ] + } + }, + { + "tableName": "PosVariationEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteProductId` INTEGER NOT NULL, `remoteVariationId` INTEGER NOT NULL, `dateModified` TEXT NOT NULL, `sku` TEXT NOT NULL, `globalUniqueId` TEXT NOT NULL, `variationName` TEXT NOT NULL, `price` TEXT NOT NULL, `regularPrice` TEXT NOT NULL, `salePrice` TEXT NOT NULL, `description` TEXT NOT NULL, `stockQuantity` REAL NOT NULL, `stockStatus` TEXT NOT NULL, `manageStock` INTEGER NOT NULL, `backordered` INTEGER NOT NULL, `attributesJson` TEXT NOT NULL, `imageUrl` TEXT NOT NULL, `status` TEXT NOT NULL, `lastUpdated` TEXT NOT NULL, `downloadable` INTEGER NOT NULL, PRIMARY KEY(`localSiteId`, `remoteProductId`, `remoteVariationId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteProductId", + "columnName": "remoteProductId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteVariationId", + "columnName": "remoteVariationId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateModified", + "columnName": "dateModified", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sku", + "columnName": "sku", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "globalUniqueId", + "columnName": "globalUniqueId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "variationName", + "columnName": "variationName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "regularPrice", + "columnName": "regularPrice", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "salePrice", + "columnName": "salePrice", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "stockQuantity", + "columnName": "stockQuantity", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "stockStatus", + "columnName": "stockStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "manageStock", + "columnName": "manageStock", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "backordered", + "columnName": "backordered", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "attributesJson", + "columnName": "attributesJson", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "imageUrl", + "columnName": "imageUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lastUpdated", + "columnName": "lastUpdated", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "downloadable", + "columnName": "downloadable", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteProductId", + "remoteVariationId" + ] + } + }, + { + "tableName": "ProductCategoryEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteCategoryId` INTEGER NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, `parent` INTEGER NOT NULL, PRIMARY KEY(`localSiteId`, `remoteCategoryId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteCategoryId", + "columnName": "remoteCategoryId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "slug", + "columnName": "slug", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "parent", + "columnName": "parent", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteCategoryId" + ] + } + }, + { + "tableName": "ProductVariationEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteProductId` INTEGER NOT NULL, `remoteVariationId` INTEGER NOT NULL, `dateCreated` TEXT NOT NULL, `dateModified` TEXT NOT NULL, `description` TEXT NOT NULL, `permalink` TEXT NOT NULL, `sku` TEXT NOT NULL, `globalUniqueId` TEXT NOT NULL, `status` TEXT NOT NULL, `price` TEXT NOT NULL, `regularPrice` TEXT NOT NULL, `salePrice` TEXT NOT NULL, `dateOnSaleFrom` TEXT NOT NULL, `dateOnSaleTo` TEXT NOT NULL, `dateOnSaleFromGmt` TEXT NOT NULL, `dateOnSaleToGmt` TEXT NOT NULL, `taxStatus` TEXT NOT NULL, `taxClass` TEXT NOT NULL, `onSale` INTEGER NOT NULL, `purchasable` INTEGER NOT NULL, `virtual` INTEGER NOT NULL, `downloadable` INTEGER NOT NULL, `downloadLimit` INTEGER NOT NULL, `downloadExpiry` INTEGER NOT NULL, `downloads` TEXT NOT NULL, `backorders` TEXT NOT NULL, `backordersAllowed` INTEGER NOT NULL, `backordered` INTEGER NOT NULL, `shippingClass` TEXT NOT NULL, `shippingClassId` INTEGER NOT NULL, `manageStock` INTEGER NOT NULL, `stockQuantity` REAL NOT NULL, `stockStatus` TEXT NOT NULL, `image` TEXT NOT NULL, `weight` TEXT NOT NULL, `length` TEXT NOT NULL, `width` TEXT NOT NULL, `height` TEXT NOT NULL, `minAllowedQuantity` INTEGER NOT NULL, `maxAllowedQuantity` INTEGER NOT NULL, `groupOfQuantity` INTEGER NOT NULL, `overrideProductQuantities` INTEGER NOT NULL, `menuOrder` INTEGER NOT NULL, `attributes` TEXT NOT NULL, `metadata` TEXT, PRIMARY KEY(`localSiteId`, `remoteProductId`, `remoteVariationId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteProductId", + "columnName": "remoteProductId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteVariationId", + "columnName": "remoteVariationId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateModified", + "columnName": "dateModified", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "permalink", + "columnName": "permalink", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sku", + "columnName": "sku", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "globalUniqueId", + "columnName": "globalUniqueId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "regularPrice", + "columnName": "regularPrice", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "salePrice", + "columnName": "salePrice", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateOnSaleFrom", + "columnName": "dateOnSaleFrom", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateOnSaleTo", + "columnName": "dateOnSaleTo", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateOnSaleFromGmt", + "columnName": "dateOnSaleFromGmt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateOnSaleToGmt", + "columnName": "dateOnSaleToGmt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "taxStatus", + "columnName": "taxStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "taxClass", + "columnName": "taxClass", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "onSale", + "columnName": "onSale", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "purchasable", + "columnName": "purchasable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "virtual", + "columnName": "virtual", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "downloadable", + "columnName": "downloadable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "downloadLimit", + "columnName": "downloadLimit", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "downloadExpiry", + "columnName": "downloadExpiry", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "downloads", + "columnName": "downloads", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "backorders", + "columnName": "backorders", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "backordersAllowed", + "columnName": "backordersAllowed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "backordered", + "columnName": "backordered", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shippingClass", + "columnName": "shippingClass", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingClassId", + "columnName": "shippingClassId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "manageStock", + "columnName": "manageStock", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "stockQuantity", + "columnName": "stockQuantity", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "stockStatus", + "columnName": "stockStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "image", + "columnName": "image", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "weight", + "columnName": "weight", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "length", + "columnName": "length", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "width", + "columnName": "width", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "height", + "columnName": "height", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "minAllowedQuantity", + "columnName": "minAllowedQuantity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "maxAllowedQuantity", + "columnName": "maxAllowedQuantity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "groupOfQuantity", + "columnName": "groupOfQuantity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "overrideProductQuantities", + "columnName": "overrideProductQuantities", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "menuOrder", + "columnName": "menuOrder", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "attributes", + "columnName": "attributes", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "metadata", + "columnName": "metadata", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteProductId", + "remoteVariationId" + ] + } + }, + { + "tableName": "ProductTagEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteTagId` INTEGER NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, `description` TEXT NOT NULL, `count` INTEGER NOT NULL, PRIMARY KEY(`localSiteId`, `remoteTagId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteTagId", + "columnName": "remoteTagId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "slug", + "columnName": "slug", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "count", + "columnName": "count", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteTagId" + ] + } + }, + { + "tableName": "ProductShippingClassEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteShippingClassId` INTEGER NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, `description` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `remoteShippingClassId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteShippingClassId", + "columnName": "remoteShippingClassId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "slug", + "columnName": "slug", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteShippingClassId" + ] + } + }, + { + "tableName": "ProductReviewEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteProductReviewId` INTEGER NOT NULL, `remoteProductId` INTEGER NOT NULL, `dateCreated` TEXT NOT NULL, `status` TEXT NOT NULL, `reviewerName` TEXT NOT NULL, `reviewerEmail` TEXT NOT NULL, `review` TEXT NOT NULL, `rating` INTEGER NOT NULL, `verified` INTEGER NOT NULL, `reviewerAvatarsJson` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `remoteProductReviewId`, `remoteProductId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteProductReviewId", + "columnName": "remoteProductReviewId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteProductId", + "columnName": "remoteProductId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "reviewerName", + "columnName": "reviewerName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "reviewerEmail", + "columnName": "reviewerEmail", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "review", + "columnName": "review", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "rating", + "columnName": "rating", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "verified", + "columnName": "verified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "reviewerAvatarsJson", + "columnName": "reviewerAvatarsJson", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteProductReviewId", + "remoteProductId" + ] + } + }, + { + "tableName": "ProductSettingsEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `weightUnit` TEXT NOT NULL, `dimensionUnit` TEXT NOT NULL, PRIMARY KEY(`localSiteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "weightUnit", + "columnName": "weightUnit", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dimensionUnit", + "columnName": "dimensionUnit", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId" + ] + } + }, + { + "tableName": "CustomerEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `localSiteId` INTEGER NOT NULL, `remoteCustomerId` INTEGER NOT NULL, `avatarUrl` TEXT NOT NULL, `dateCreated` TEXT NOT NULL, `dateCreatedGmt` TEXT NOT NULL, `dateModified` TEXT NOT NULL, `dateModifiedGmt` TEXT NOT NULL, `email` TEXT NOT NULL, `firstName` TEXT NOT NULL, `isPayingCustomer` INTEGER NOT NULL, `lastName` TEXT NOT NULL, `role` TEXT NOT NULL, `username` TEXT NOT NULL, `billingAddress1` TEXT NOT NULL, `billingAddress2` TEXT NOT NULL, `billingCity` TEXT NOT NULL, `billingCompany` TEXT NOT NULL, `billingCountry` TEXT NOT NULL, `billingEmail` TEXT NOT NULL, `billingFirstName` TEXT NOT NULL, `billingLastName` TEXT NOT NULL, `billingPhone` TEXT NOT NULL, `billingPostcode` TEXT NOT NULL, `billingState` TEXT NOT NULL, `shippingAddress1` TEXT NOT NULL, `shippingAddress2` TEXT NOT NULL, `shippingCity` TEXT NOT NULL, `shippingCompany` TEXT NOT NULL, `shippingCountry` TEXT NOT NULL, `shippingFirstName` TEXT NOT NULL, `shippingLastName` TEXT NOT NULL, `shippingPostcode` TEXT NOT NULL, `shippingState` TEXT NOT NULL, `analyticsCustomerId` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteCustomerId", + "columnName": "remoteCustomerId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "avatarUrl", + "columnName": "avatarUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateCreatedGmt", + "columnName": "dateCreatedGmt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateModified", + "columnName": "dateModified", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateModifiedGmt", + "columnName": "dateModifiedGmt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "firstName", + "columnName": "firstName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isPayingCustomer", + "columnName": "isPayingCustomer", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastName", + "columnName": "lastName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "role", + "columnName": "role", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "username", + "columnName": "username", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingAddress1", + "columnName": "billingAddress1", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingAddress2", + "columnName": "billingAddress2", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingCity", + "columnName": "billingCity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingCompany", + "columnName": "billingCompany", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingCountry", + "columnName": "billingCountry", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingEmail", + "columnName": "billingEmail", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingFirstName", + "columnName": "billingFirstName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingLastName", + "columnName": "billingLastName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingPhone", + "columnName": "billingPhone", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingPostcode", + "columnName": "billingPostcode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingState", + "columnName": "billingState", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingAddress1", + "columnName": "shippingAddress1", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingAddress2", + "columnName": "shippingAddress2", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingCity", + "columnName": "shippingCity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingCompany", + "columnName": "shippingCompany", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingCountry", + "columnName": "shippingCountry", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingFirstName", + "columnName": "shippingFirstName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingLastName", + "columnName": "shippingLastName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingPostcode", + "columnName": "shippingPostcode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingState", + "columnName": "shippingState", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "analyticsCustomerId", + "columnName": "analyticsCustomerId", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "LocationEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`parentCode` TEXT NOT NULL, `code` TEXT NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`parentCode`, `code`))", + "fields": [ + { + "fieldPath": "parentCode", + "columnName": "parentCode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "code", + "columnName": "code", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "parentCode", + "code" + ] + } + }, + { + "tableName": "OrderShipmentProviderEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `country` TEXT NOT NULL, `carrierName` TEXT NOT NULL, `carrierLink` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `carrierName`, `country`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "country", + "columnName": "country", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "carrierName", + "columnName": "carrierName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "carrierLink", + "columnName": "carrierLink", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "carrierName", + "country" + ] + } + }, + { + "tableName": "UserEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteUserId` INTEGER NOT NULL, `firstName` TEXT NOT NULL, `lastName` TEXT NOT NULL, `username` TEXT NOT NULL, `email` TEXT NOT NULL, `roles` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `remoteUserId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteUserId", + "columnName": "remoteUserId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "firstName", + "columnName": "firstName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lastName", + "columnName": "lastName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "username", + "columnName": "username", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roles", + "columnName": "roles", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteUserId" + ] + } + }, + { + "tableName": "TaxClassEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `slug`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "slug", + "columnName": "slug", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "slug" + ] + } + }, + { + "tableName": "SettingsEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `currencyCode` TEXT NOT NULL, `currencyPosition` TEXT NOT NULL, `currencyThousandSeparator` TEXT NOT NULL, `currencyDecimalSeparator` TEXT NOT NULL, `currencyDecimalNumber` INTEGER NOT NULL, `countryCode` TEXT NOT NULL, `stateCode` TEXT NOT NULL, `address` TEXT NOT NULL, `address2` TEXT NOT NULL, `city` TEXT NOT NULL, `postalCode` TEXT NOT NULL, `couponsEnabled` INTEGER NOT NULL, PRIMARY KEY(`localSiteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "currencyCode", + "columnName": "currencyCode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currencyPosition", + "columnName": "currencyPosition", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currencyThousandSeparator", + "columnName": "currencyThousandSeparator", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currencyDecimalSeparator", + "columnName": "currencyDecimalSeparator", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currencyDecimalNumber", + "columnName": "currencyDecimalNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "countryCode", + "columnName": "countryCode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "stateCode", + "columnName": "stateCode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "address2", + "columnName": "address2", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "city", + "columnName": "city", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "postalCode", + "columnName": "postalCode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "couponsEnabled", + "columnName": "couponsEnabled", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId" + ] + } + }, + { + "tableName": "OrderSummaryEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`siteId` INTEGER NOT NULL, `orderId` INTEGER NOT NULL, `dateCreated` TEXT NOT NULL, PRIMARY KEY(`siteId`, `orderId`))", + "fields": [ + { + "fieldPath": "siteId", + "columnName": "siteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "orderId", + "columnName": "orderId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "siteId", + "orderId" + ] + } + }, + { + "tableName": "OrderStatusEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`siteId` INTEGER NOT NULL, `statusKey` TEXT NOT NULL, `label` TEXT NOT NULL, `statusCount` INTEGER NOT NULL, `position` INTEGER NOT NULL, PRIMARY KEY(`siteId`, `statusKey`))", + "fields": [ + { + "fieldPath": "siteId", + "columnName": "siteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "statusKey", + "columnName": "statusKey", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "label", + "columnName": "label", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "statusCount", + "columnName": "statusCount", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "position", + "columnName": "position", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "siteId", + "statusKey" + ] + } + }, + { + "tableName": "WooShippingLabelEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `orderId` INTEGER NOT NULL, `labelId` INTEGER NOT NULL, `tracking` TEXT NOT NULL, `refundableAmount` TEXT NOT NULL, `status` TEXT NOT NULL, `created` TEXT, `carrierId` TEXT NOT NULL, `serviceName` TEXT NOT NULL, `commercialInvoiceUrl` TEXT, `isCommercialInvoiceSubmittedElectronically` INTEGER NOT NULL, `packageName` TEXT NOT NULL, `isLetter` INTEGER NOT NULL, `productNames` TEXT NOT NULL, `productIds` TEXT, `shipmentId` TEXT, `receiptItemId` INTEGER NOT NULL, `createdDate` TEXT, `mainReceiptId` INTEGER NOT NULL, `rate` TEXT NOT NULL, `currency` TEXT NOT NULL, `expiryDate` INTEGER NOT NULL, `usedDate` INTEGER, `refund` TEXT, `hazmatCategory` TEXT, `originAddress` TEXT, `destinationAddress` TEXT, PRIMARY KEY(`localSiteId`, `orderId`, `labelId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "orderId", + "columnName": "orderId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "labelId", + "columnName": "labelId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "tracking", + "columnName": "tracking", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "refundableAmount", + "columnName": "refundableAmount", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "created", + "columnName": "created", + "affinity": "TEXT" + }, + { + "fieldPath": "carrierId", + "columnName": "carrierId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "serviceName", + "columnName": "serviceName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "commercialInvoiceUrl", + "columnName": "commercialInvoiceUrl", + "affinity": "TEXT" + }, + { + "fieldPath": "isCommercialInvoiceSubmittedElectronically", + "columnName": "isCommercialInvoiceSubmittedElectronically", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "packageName", + "columnName": "packageName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isLetter", + "columnName": "isLetter", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "productNames", + "columnName": "productNames", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "productIds", + "columnName": "productIds", + "affinity": "TEXT" + }, + { + "fieldPath": "shipmentId", + "columnName": "shipmentId", + "affinity": "TEXT" + }, + { + "fieldPath": "receiptItemId", + "columnName": "receiptItemId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "createdDate", + "columnName": "createdDate", + "affinity": "TEXT" + }, + { + "fieldPath": "mainReceiptId", + "columnName": "mainReceiptId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "rate", + "columnName": "rate", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "expiryDate", + "columnName": "expiryDate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "usedDate", + "columnName": "usedDate", + "affinity": "INTEGER" + }, + { + "fieldPath": "refund", + "columnName": "refund", + "affinity": "TEXT" + }, + { + "fieldPath": "hazmatCategory", + "columnName": "hazmatCategory", + "affinity": "TEXT" + }, + { + "fieldPath": "originAddress", + "columnName": "originAddress", + "affinity": "TEXT" + }, + { + "fieldPath": "destinationAddress", + "columnName": "destinationAddress", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "orderId", + "labelId" + ] + } + }, + { + "tableName": "WooShippingShipmentEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `orderId` INTEGER NOT NULL, `shipmentId` TEXT NOT NULL, `items` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `orderId`, `shipmentId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "orderId", + "columnName": "orderId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shipmentId", + "columnName": "shipmentId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "items", + "columnName": "items", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "orderId", + "shipmentId" + ] + } + }, + { + "tableName": "WooShippingPackagesEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `storeOptions` TEXT NOT NULL, `savedPackages` TEXT NOT NULL, `carrierPackageGroups` TEXT NOT NULL, PRIMARY KEY(`localSiteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "storeOptions", + "columnName": "storeOptions", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "savedPackages", + "columnName": "savedPackages", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "carrierPackageGroups", + "columnName": "carrierPackageGroups", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId" + ] + } + }, + { + "tableName": "GlobalAttributeEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`siteId` INTEGER NOT NULL, `remoteId` INTEGER NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, `type` TEXT NOT NULL, `orderBy` TEXT NOT NULL, `hasArchives` INTEGER NOT NULL, PRIMARY KEY(`siteId`, `remoteId`))", + "fields": [ + { + "fieldPath": "siteId", + "columnName": "siteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "slug", + "columnName": "slug", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "orderBy", + "columnName": "orderBy", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "hasArchives", + "columnName": "hasArchives", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "siteId", + "remoteId" + ] + } + }, + { + "tableName": "GatewayEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`siteId` INTEGER NOT NULL, `gatewayId` TEXT NOT NULL, `data` TEXT NOT NULL, PRIMARY KEY(`siteId`, `gatewayId`))", + "fields": [ + { + "fieldPath": "siteId", + "columnName": "siteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "gatewayId", + "columnName": "gatewayId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "data", + "columnName": "data", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "siteId", + "gatewayId" + ] + } + } + ], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'c10399e20f850a169d96cac1e3b92dfd')" + ] + } +} \ No newline at end of file diff --git a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt index 216c28790c58..27dcafabae16 100644 --- a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt +++ b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt @@ -86,6 +86,7 @@ import org.wordpress.android.fluxc.persistence.entity.WooPaymentsDepositEntity import org.wordpress.android.fluxc.persistence.entity.WooPaymentsDepositsOverviewEntity import org.wordpress.android.fluxc.persistence.entity.WooPaymentsManualDepositEntity import org.wordpress.android.fluxc.persistence.entity.WooShippingLabelEntity +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity import org.wordpress.android.fluxc.persistence.entity.WooShippingShipmentEntity import org.wordpress.android.fluxc.persistence.entity.pos.WCPosProductEntity import org.wordpress.android.fluxc.persistence.entity.pos.WCPosVariationModel @@ -117,7 +118,7 @@ import org.wordpress.android.fluxc.persistence.migrations.MIGRATION_7_8 import org.wordpress.android.fluxc.persistence.migrations.MIGRATION_8_9 import org.wordpress.android.fluxc.persistence.migrations.MIGRATION_9_10 -const val WC_DATABASE_VERSION = 63 +const val WC_DATABASE_VERSION = 64 @Database( version = WC_DATABASE_VERSION, @@ -162,6 +163,7 @@ const val WC_DATABASE_VERSION = 63 WCOrderStatusModel::class, WooShippingLabelEntity::class, WooShippingShipmentEntity::class, + WooShippingPackagesEntity::class, WCGlobalAttributeModel::class, GatewayEntity::class, ], @@ -209,6 +211,7 @@ const val WC_DATABASE_VERSION = 63 AutoMigration(from = 59, to = 60), AutoMigration(from = 60, to = 61), AutoMigration(from = 61, to = 62), + AutoMigration(from = 63, to = 64), ] ) @TypeConverters( diff --git a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/WooShippingDao.kt b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/WooShippingDao.kt index 335e78d34794..d1fb859d8018 100644 --- a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/WooShippingDao.kt +++ b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/WooShippingDao.kt @@ -7,6 +7,7 @@ import androidx.room.Upsert import kotlinx.coroutines.flow.Flow import org.wordpress.android.fluxc.model.LocalOrRemoteId import org.wordpress.android.fluxc.persistence.entity.WooShippingLabelEntity +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity import org.wordpress.android.fluxc.persistence.entity.WooShippingShipmentEntity @Dao @@ -106,4 +107,13 @@ abstract class WooShippingDao { deleteShipments(localSiteId, orderId) insertShipments(shipments) } + + @Upsert + abstract suspend fun insertShippingPackages(packages: WooShippingPackagesEntity) + + @Query("SELECT * FROM WooShippingPackagesEntity WHERE localSiteId = :localSiteId") + abstract suspend fun getShippingPackages(localSiteId: LocalOrRemoteId.LocalId): WooShippingPackagesEntity? + + @Query("SELECT * FROM WooShippingPackagesEntity WHERE localSiteId = :localSiteId") + abstract fun observeShippingPackages(localSiteId: LocalOrRemoteId.LocalId): Flow } diff --git a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/entity/WooShippingPackagesEntity.kt b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/entity/WooShippingPackagesEntity.kt new file mode 100644 index 000000000000..95e00e107d08 --- /dev/null +++ b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/entity/WooShippingPackagesEntity.kt @@ -0,0 +1,169 @@ +package org.wordpress.android.fluxc.persistence.entity + +import androidx.room.Entity +import androidx.room.TypeConverter +import androidx.room.TypeConverters +import com.google.gson.JsonArray +import com.google.gson.JsonObject +import com.google.gson.JsonParser +import org.wordpress.android.fluxc.model.LocalOrRemoteId +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity.CarrierPackageGroup +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity.CarrierPackageGroups +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity.CarrierType +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity.Package +import org.wordpress.android.fluxc.persistence.entity.WooShippingPackagesEntity.StoreOptions +import org.wordpress.android.fluxc.utils.asStringOrNull + +@Entity(primaryKeys = ["localSiteId"]) +@TypeConverters(WooShippingPackagesConverters::class) +data class WooShippingPackagesEntity( + val localSiteId: LocalOrRemoteId.LocalId, + val storeOptions: StoreOptions, + val savedPackages: List, + val carrierPackageGroups: List +) { + data class StoreOptions( + val currencySymbol: String?, + val dimensionUnit: String?, + val weightUnit: String?, + val originCountry: String? + ) + + data class Package( + val id: String?, + val name: String?, + val dimensions: String?, + val weight: String?, + val isLetter: Boolean, + val dimensionUnit: String?, + val isUserDefined: Boolean = false, + val weightUnit: String?, + val groupName: String? = null, + val saved: Boolean + ) + + data class CarrierPackageGroups( + val carrierType: CarrierType?, + val packageGroups: List? + ) + + data class CarrierPackageGroup(val description: String?, val packages: List?) + + enum class CarrierType(val id: String) { + USPS("usps"), + DHL("dhlexpress"), + UPS("upsdap"); + + companion object { + fun fromId(id: String): CarrierType? = entries.firstOrNull { it.id == id } + } + } +} + +internal class WooShippingPackagesConverters { + @TypeConverter + fun fromStoreOptions(storeOptions: StoreOptions?): String? = storeOptions?.let { + JsonObject().apply { + addProperty("currency_symbol", it.currencySymbol) + addProperty("dimension_unit", it.dimensionUnit) + addProperty("weight_unit", it.weightUnit) + addProperty("origin_country", it.originCountry) + }.toString() + } + + @TypeConverter + fun toStoreOptions(value: String?): StoreOptions? = value?.let { json -> + JsonParser.parseString(json).asJsonObject.let { jsonObject -> + StoreOptions( + currencySymbol = jsonObject.get("currency_symbol")?.asStringOrNull, + dimensionUnit = jsonObject.get("dimension_unit")?.asStringOrNull, + weightUnit = jsonObject.get("weight_unit")?.asStringOrNull, + originCountry = jsonObject.get("origin_country")?.asStringOrNull + ) + } + } + + @TypeConverter + fun fromPackageList(value: List?): String? = value?.let { + JsonArray().apply { + it.forEach { item -> + add( + JsonObject().apply { + addProperty("id", item.id) + addProperty("name", item.name) + addProperty("dimensions", item.dimensions) + addProperty("weight", item.weight) + addProperty("is_letter", item.isLetter) + addProperty("dimension_unit", item.dimensionUnit) + addProperty("is_user_defined", item.isUserDefined) + addProperty("weight_unit", item.weightUnit) + addProperty("group_name", item.groupName) + addProperty("saved", item.saved) + } + ) + } + }.toString() + } + + @TypeConverter + fun toPackageList(value: String?): List? = value?.let { + JsonParser.parseString(it).asJsonArray.mapNotNull { jsonElement -> + val jsonObject = jsonElement as? JsonObject ?: return null + Package( + id = jsonObject.get("id")?.asStringOrNull, + name = jsonObject.get("name")?.asStringOrNull, + dimensions = jsonObject.get("dimensions")?.asStringOrNull, + weight = jsonObject.get("weight")?.asStringOrNull, + isLetter = jsonObject.get("is_letter")?.asBoolean == true, + dimensionUnit = jsonObject.get("dimension_unit")?.asStringOrNull, + isUserDefined = jsonObject.get("is_user_defined")?.asBoolean == true, + weightUnit = jsonObject.get("weight_unit")?.asStringOrNull, + groupName = jsonObject.get("group_name")?.asStringOrNull, + saved = jsonObject.get("saved")?.asBoolean == true, + ) + } + } + + @TypeConverter + fun fromCarrierPackageGroups(value: List?): String? = value?.let { + JsonArray().apply { + it.forEach { item -> + add( + JsonObject().apply { + addProperty("carrier_type", item.carrierType?.id) + val packageGroups = JsonArray().apply { + item.packageGroups?.forEach { packageGroup -> + add( + JsonObject().apply { + addProperty("description", packageGroup.description) + addProperty("packages", fromPackageList(packageGroup.packages)) + } + ) + } + } + add("package_groups", packageGroups) + } + ) + } + }.toString() + } + + @TypeConverter + fun toCarrierPackageGroups(value: String?): List? = value?.let { + JsonParser.parseString(it).asJsonArray.mapNotNull { jsonElement -> + val jsonObject = jsonElement as? JsonObject ?: return null + CarrierPackageGroups( + carrierType = jsonObject.get("carrier_type")?.asStringOrNull?.let { id -> CarrierType.fromId(id) }, + packageGroups = toPackageGroups(jsonObject.getAsJsonArray("package_groups")), + ) + } + } + + private fun toPackageGroups(value: JsonArray?): List? = value?.mapNotNull { jsonElement -> + val jsonObject = jsonElement as? JsonObject ?: return null + CarrierPackageGroup( + description = jsonObject.get("description")?.asStringOrNull, + packages = toPackageList(jsonObject.get("packages")?.asStringOrNull), + ) + } +}