From 7b74a3475d3d82538dfb082e006d191a1ef082df Mon Sep 17 00:00:00 2001 From: Thomas Horta Date: Thu, 31 Aug 2023 15:07:54 -0300 Subject: [PATCH 01/55] Update compileSdkVersion to 34 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 39840c807f..a46f7526f1 100644 --- a/build.gradle +++ b/build.gradle @@ -61,7 +61,7 @@ allprojects { ext { minSdkVersion = 24 - compileSdkVersion = 33 + compileSdkVersion = 34 targetSdkVersion = 33 } From 0a36e4d2559fdbafe99ee87166cc0c6e3210c5ed Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Tue, 5 Sep 2023 08:51:04 -0400 Subject: [PATCH 02/55] Add new Tax rate endpoint --- .../android/fluxc/di/WCDatabaseModule.kt | 2 ++ .../fluxc/model/taxes/TaxRateEntity.kt | 10 +++++++ .../rest/wpcom/wc/taxes/WCTaxRestClient.kt | 28 +++++++++++++++++++ .../fluxc/persistence/WCAndroidDatabase.kt | 4 +++ .../fluxc/persistence/dao/TaxRateDao.kt | 11 ++++++++ .../android/fluxc/store/WCTaxStore.kt | 21 ++++++++++++++ 6 files changed, 76 insertions(+) create mode 100644 plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt create mode 100644 plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/di/WCDatabaseModule.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/di/WCDatabaseModule.kt index f2f6b4d55a..84258603a9 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/di/WCDatabaseModule.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/di/WCDatabaseModule.kt @@ -44,6 +44,8 @@ interface WCDatabaseModule { @Provides fun provideTopPerformerProductsDao(database: WCAndroidDatabase) = database.topPerformerProductsDao @Provides fun provideTaxBasedOnDao(database: WCAndroidDatabase) = database.taxBasedOnSettingDao + + @Provides fun provideTaxRateDao(database: WCAndroidDatabase) = database.taxRateDao } @Binds fun bindTransactionExecutor(database: WCAndroidDatabase): TransactionExecutor } diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt new file mode 100644 index 0000000000..9191f213ee --- /dev/null +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt @@ -0,0 +1,10 @@ +package org.wordpress.android.fluxc.model.taxes + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "TaxRate") +data class TaxRateEntity ( + @PrimaryKey val localSiteId: Long, + val id: Long, +) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/WCTaxRestClient.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/WCTaxRestClient.kt index 32a25ac72a..ecc3981d35 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/WCTaxRestClient.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/WCTaxRestClient.kt @@ -23,8 +23,36 @@ class WCTaxRestClient @Inject constructor(private val wooNetwork: WooNetwork) { return response.toWooPayload() } + suspend fun fetchTaxRateList(site: SiteModel): WooPayload> { + val url = WOOCOMMERCE.taxes.pathV3 + + val response = wooNetwork.executeGetGsonRequest( + site, + url, + Array::class.java + ) + return response.toWooPayload() + } + data class TaxClassApiResponse( val name: String? = null, val slug: String? = null ) + + data class TaxRateApiResponse( + val id: Int, + val country: String = "", + val state: String = "", + val postcode: String = "", + val city: String = "", + val postCodes: List? = null, + val cities: List? = null, + val rate: String = "", + val name: String = "", + val priority: Int = 0, + val compound: Boolean = false, + val shipping: Boolean = false, + val order: Int = 0, + val taxClass: String = "", + ) } diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt index 8061b85dcd..059854480b 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt @@ -9,6 +9,7 @@ import androidx.room.TypeConverters import androidx.room.withTransaction import org.wordpress.android.fluxc.model.OrderEntity import org.wordpress.android.fluxc.model.taxes.TaxBasedOnSettingEntity +import org.wordpress.android.fluxc.model.taxes.TaxRateEntity import org.wordpress.android.fluxc.persistence.converters.BigDecimalConverter import org.wordpress.android.fluxc.persistence.converters.LocalIdConverter import org.wordpress.android.fluxc.persistence.converters.LongListConverter @@ -20,6 +21,7 @@ import org.wordpress.android.fluxc.persistence.dao.OrderMetaDataDao import org.wordpress.android.fluxc.persistence.dao.OrderNotesDao import org.wordpress.android.fluxc.persistence.dao.OrdersDao import org.wordpress.android.fluxc.persistence.dao.TaxBasedOnDao +import org.wordpress.android.fluxc.persistence.dao.TaxRateDao import org.wordpress.android.fluxc.persistence.dao.TopPerformerProductsDao import org.wordpress.android.fluxc.persistence.entity.AddonEntity import org.wordpress.android.fluxc.persistence.entity.AddonOptionEntity @@ -68,6 +70,7 @@ import org.wordpress.android.fluxc.persistence.migrations.MIGRATION_9_10 InboxNoteActionEntity::class, TopPerformerProductEntity::class, TaxBasedOnSettingEntity::class, + TaxRateEntity::class ], autoMigrations = [ AutoMigration(from = 12, to = 13), @@ -98,6 +101,7 @@ abstract class WCAndroidDatabase : RoomDatabase(), TransactionExecutor { abstract val inboxNotesDao: InboxNotesDao abstract val topPerformerProductsDao: TopPerformerProductsDao abstract val taxBasedOnSettingDao: TaxBasedOnDao + abstract val taxRateDao: TaxRateDao companion object { fun buildDb(applicationContext: Context) = Room.databaseBuilder( diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt new file mode 100644 index 0000000000..73b0c862b7 --- /dev/null +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt @@ -0,0 +1,11 @@ +package org.wordpress.android.fluxc.persistence.dao + +import androidx.room.Dao +import androidx.room.Query +import org.wordpress.android.fluxc.model.taxes.TaxRateEntity + +@Dao +interface TaxRateDao { + @Query("SELECT * FROM TaxRate WHERE localSiteId = :localSiteId") + suspend fun getTaxRateList(localSiteId: Long): List +} diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt index 4c4f9ecb8e..f67fe5e4d0 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt @@ -1,6 +1,7 @@ package org.wordpress.android.fluxc.store import org.wordpress.android.fluxc.model.SiteModel +import org.wordpress.android.fluxc.model.taxes.TaxRateEntity import org.wordpress.android.fluxc.model.taxes.WCTaxClassMapper import org.wordpress.android.fluxc.model.taxes.WCTaxClassModel import org.wordpress.android.fluxc.network.BaseRequest.GenericErrorType.UNKNOWN @@ -47,4 +48,24 @@ class WCTaxStore @Inject constructor( } } } + suspend fun fetchTaxRateList(site: SiteModel): WooResult> { + return coroutineEngine.withDefaultContext(AppLog.T.API, this, "fetchTaxRateList") { + val response = restClient.fetchTaxRateList(site) + return@withDefaultContext when { + response.isError -> { + WooResult(response.error) + } + response.result != null -> { + val taxRateEntities = response.result.map { + TaxRateEntity( + localSiteId = site.id.toLong(), + id = it.id.toLong() + ) + } + WooResult(taxRateEntities) + } + else -> WooResult(WooError(GENERIC_ERROR, UNKNOWN)) + } + } + } } From 6df719aa98d58d25f4fc631aee04dcdee7eb1562 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Wed, 6 Sep 2023 09:08:29 -0400 Subject: [PATCH 03/55] Add auto migration --- .../org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt index 059854480b..e863efeff1 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt @@ -82,6 +82,7 @@ import org.wordpress.android.fluxc.persistence.migrations.MIGRATION_9_10 AutoMigration(from = 19, to = 20, spec = AutoMigration19to20::class), AutoMigration(from = 23, to = 24, spec = AutoMigration23to24::class), AutoMigration(from = 25, to = 26), + AutoMigration(from = 26, to = 27) ] ) @TypeConverters( From b8ad2310333ece0105dcb8f52a3644cf88d2ffe1 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Wed, 6 Sep 2023 10:02:45 -0400 Subject: [PATCH 04/55] Add paginated results --- .../rest/wpcom/wc/taxes/WCTaxRestClient.kt | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/WCTaxRestClient.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/WCTaxRestClient.kt index ecc3981d35..06184226c2 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/WCTaxRestClient.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/WCTaxRestClient.kt @@ -2,8 +2,10 @@ package org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes import org.wordpress.android.fluxc.generated.endpoint.WOOCOMMERCE import org.wordpress.android.fluxc.model.SiteModel +import org.wordpress.android.fluxc.network.rest.wpapi.WPAPIResponse import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooNetwork import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooPayload +import org.wordpress.android.fluxc.network.rest.wpcom.wc.toWooError import org.wordpress.android.fluxc.utils.toWooPayload import javax.inject.Inject import javax.inject.Singleton @@ -23,15 +25,34 @@ class WCTaxRestClient @Inject constructor(private val wooNetwork: WooNetwork) { return response.toWooPayload() } - suspend fun fetchTaxRateList(site: SiteModel): WooPayload> { + suspend fun fetchTaxRateList( + site: SiteModel, + page: Int, + pageSize: Int, + searchQuery: String? = null + ): WooPayload> { val url = WOOCOMMERCE.taxes.pathV3 val response = wooNetwork.executeGetGsonRequest( site, url, - Array::class.java + Array::class.java, + mutableMapOf().apply { + put("page", page.toString()) + put("per_page", pageSize.toString()) + searchQuery?.let { + put("search", searchQuery) + } + } ) - return response.toWooPayload() + return when (response) { + is WPAPIResponse.Success -> { + WooPayload(response.data) + } + is WPAPIResponse.Error -> { + WooPayload(response.error.toWooError()) + } + } } data class TaxClassApiResponse( From 9cc8f39ccb5a4b46c2db8c83c893ab7bec33bf13 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Wed, 6 Sep 2023 15:53:13 -0400 Subject: [PATCH 05/55] Remove Room - will not store tax rates in the DB --- .../wordpress/android/fluxc/di/WCDatabaseModule.kt | 2 -- .../android/fluxc/model/taxes/TaxRateEntity.kt | 10 ---------- .../android/fluxc/persistence/WCAndroidDatabase.kt | 5 ----- .../android/fluxc/persistence/dao/TaxRateDao.kt | 11 ----------- 4 files changed, 28 deletions(-) delete mode 100644 plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt delete mode 100644 plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/di/WCDatabaseModule.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/di/WCDatabaseModule.kt index 84258603a9..f2f6b4d55a 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/di/WCDatabaseModule.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/di/WCDatabaseModule.kt @@ -44,8 +44,6 @@ interface WCDatabaseModule { @Provides fun provideTopPerformerProductsDao(database: WCAndroidDatabase) = database.topPerformerProductsDao @Provides fun provideTaxBasedOnDao(database: WCAndroidDatabase) = database.taxBasedOnSettingDao - - @Provides fun provideTaxRateDao(database: WCAndroidDatabase) = database.taxRateDao } @Binds fun bindTransactionExecutor(database: WCAndroidDatabase): TransactionExecutor } diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt deleted file mode 100644 index 9191f213ee..0000000000 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt +++ /dev/null @@ -1,10 +0,0 @@ -package org.wordpress.android.fluxc.model.taxes - -import androidx.room.Entity -import androidx.room.PrimaryKey - -@Entity(tableName = "TaxRate") -data class TaxRateEntity ( - @PrimaryKey val localSiteId: Long, - val id: Long, -) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt index e863efeff1..8061b85dcd 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt @@ -9,7 +9,6 @@ import androidx.room.TypeConverters import androidx.room.withTransaction import org.wordpress.android.fluxc.model.OrderEntity import org.wordpress.android.fluxc.model.taxes.TaxBasedOnSettingEntity -import org.wordpress.android.fluxc.model.taxes.TaxRateEntity import org.wordpress.android.fluxc.persistence.converters.BigDecimalConverter import org.wordpress.android.fluxc.persistence.converters.LocalIdConverter import org.wordpress.android.fluxc.persistence.converters.LongListConverter @@ -21,7 +20,6 @@ import org.wordpress.android.fluxc.persistence.dao.OrderMetaDataDao import org.wordpress.android.fluxc.persistence.dao.OrderNotesDao import org.wordpress.android.fluxc.persistence.dao.OrdersDao import org.wordpress.android.fluxc.persistence.dao.TaxBasedOnDao -import org.wordpress.android.fluxc.persistence.dao.TaxRateDao import org.wordpress.android.fluxc.persistence.dao.TopPerformerProductsDao import org.wordpress.android.fluxc.persistence.entity.AddonEntity import org.wordpress.android.fluxc.persistence.entity.AddonOptionEntity @@ -70,7 +68,6 @@ import org.wordpress.android.fluxc.persistence.migrations.MIGRATION_9_10 InboxNoteActionEntity::class, TopPerformerProductEntity::class, TaxBasedOnSettingEntity::class, - TaxRateEntity::class ], autoMigrations = [ AutoMigration(from = 12, to = 13), @@ -82,7 +79,6 @@ import org.wordpress.android.fluxc.persistence.migrations.MIGRATION_9_10 AutoMigration(from = 19, to = 20, spec = AutoMigration19to20::class), AutoMigration(from = 23, to = 24, spec = AutoMigration23to24::class), AutoMigration(from = 25, to = 26), - AutoMigration(from = 26, to = 27) ] ) @TypeConverters( @@ -102,7 +98,6 @@ abstract class WCAndroidDatabase : RoomDatabase(), TransactionExecutor { abstract val inboxNotesDao: InboxNotesDao abstract val topPerformerProductsDao: TopPerformerProductsDao abstract val taxBasedOnSettingDao: TaxBasedOnDao - abstract val taxRateDao: TaxRateDao companion object { fun buildDb(applicationContext: Context) = Room.databaseBuilder( diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt deleted file mode 100644 index 73b0c862b7..0000000000 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt +++ /dev/null @@ -1,11 +0,0 @@ -package org.wordpress.android.fluxc.persistence.dao - -import androidx.room.Dao -import androidx.room.Query -import org.wordpress.android.fluxc.model.taxes.TaxRateEntity - -@Dao -interface TaxRateDao { - @Query("SELECT * FROM TaxRate WHERE localSiteId = :localSiteId") - suspend fun getTaxRateList(localSiteId: Long): List -} From 48039a9f6442195f1537a2c98c67512cd0349ff9 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Wed, 6 Sep 2023 16:04:25 -0400 Subject: [PATCH 06/55] Add pagination --- .../fluxc/network/rest/wpcom/wc/taxes/WCTaxRestClient.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/WCTaxRestClient.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/WCTaxRestClient.kt index 06184226c2..b6f4308704 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/WCTaxRestClient.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/WCTaxRestClient.kt @@ -29,7 +29,6 @@ class WCTaxRestClient @Inject constructor(private val wooNetwork: WooNetwork) { site: SiteModel, page: Int, pageSize: Int, - searchQuery: String? = null ): WooPayload> { val url = WOOCOMMERCE.taxes.pathV3 @@ -40,9 +39,6 @@ class WCTaxRestClient @Inject constructor(private val wooNetwork: WooNetwork) { mutableMapOf().apply { put("page", page.toString()) put("per_page", pageSize.toString()) - searchQuery?.let { - put("search", searchQuery) - } } ) return when (response) { From 41e027ab0cdcf3609879ef5547e4b4deda9333c4 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Wed, 6 Sep 2023 16:04:49 -0400 Subject: [PATCH 07/55] Expose FetchTaxRateList in WCTaxStore --- .../android/fluxc/store/WCTaxStore.kt | 24 ++++--------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt index f67fe5e4d0..6ba198aed5 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt @@ -1,14 +1,15 @@ package org.wordpress.android.fluxc.store import org.wordpress.android.fluxc.model.SiteModel -import org.wordpress.android.fluxc.model.taxes.TaxRateEntity import org.wordpress.android.fluxc.model.taxes.WCTaxClassMapper import org.wordpress.android.fluxc.model.taxes.WCTaxClassModel 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.network.rest.wpcom.wc.WooResult import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient +import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient.TaxRateApiResponse import org.wordpress.android.fluxc.persistence.WCTaxSqlUtils import org.wordpress.android.fluxc.tools.CoroutineEngine import org.wordpress.android.util.AppLog @@ -48,24 +49,7 @@ class WCTaxStore @Inject constructor( } } } - suspend fun fetchTaxRateList(site: SiteModel): WooResult> { - return coroutineEngine.withDefaultContext(AppLog.T.API, this, "fetchTaxRateList") { - val response = restClient.fetchTaxRateList(site) - return@withDefaultContext when { - response.isError -> { - WooResult(response.error) - } - response.result != null -> { - val taxRateEntities = response.result.map { - TaxRateEntity( - localSiteId = site.id.toLong(), - id = it.id.toLong() - ) - } - WooResult(taxRateEntities) - } - else -> WooResult(WooError(GENERIC_ERROR, UNKNOWN)) - } - } + suspend fun fetchTaxRateList(site: SiteModel): WooPayload> { + return restClient.fetchTaxRateList(site, 1, 100) } } From 9aa6b4fd97255c544b755b825b64351cd76c8512 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 6 Sep 2023 17:19:22 -0300 Subject: [PATCH 08/55] Add support for params in ProductAttributeRestClient GET requests --- .../wc/product/attributes/ProductAttributeRestClient.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/product/attributes/ProductAttributeRestClient.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/product/attributes/ProductAttributeRestClient.kt index 3b3044b3f5..4b5518b8b2 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/product/attributes/ProductAttributeRestClient.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/product/attributes/ProductAttributeRestClient.kt @@ -69,11 +69,13 @@ class ProductAttributeRestClient @Inject constructor(private val wooNetwork: Woo .delete(site) private suspend inline fun String.request( - site: SiteModel + site: SiteModel, + params: Map = emptyMap() ) = wooNetwork.executeGetGsonRequest( site = site, path = this, - clazz = T::class.java + clazz = T::class.java, + params = params ).toWooPayload() private suspend inline fun String.post( From 25d30f072bda8c710b121c6fa2f7b74accc551c0 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 6 Sep 2023 17:28:14 -0300 Subject: [PATCH 09/55] Introduce per_page parameter to Attribute terms fetching with default of 100 as page size --- .../wc/product/attributes/ProductAttributeRestClient.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/product/attributes/ProductAttributeRestClient.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/product/attributes/ProductAttributeRestClient.kt index 4b5518b8b2..81279d6947 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/product/attributes/ProductAttributeRestClient.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/product/attributes/ProductAttributeRestClient.kt @@ -42,9 +42,13 @@ class ProductAttributeRestClient @Inject constructor(private val wooNetwork: Woo suspend fun fetchAllAttributeTerms( site: SiteModel, - attributeID: Long + attributeID: Long, + pageSize: Int = 100 ) = WOOCOMMERCE.products.attributes.attribute(attributeID).terms.pathV3 - .request>(site) + .request>( + site = site, + params = mapOf("per_page" to pageSize.toString()) + ) suspend fun postNewTerm( site: SiteModel, From c16c99e09bdadb4a6949bb299ae1b833929af3c5 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Wed, 6 Sep 2023 16:57:02 -0400 Subject: [PATCH 10/55] Add tests --- .../android/fluxc/wc/taxes/TaxTestUtils.kt | 9 ++++++++ .../android/fluxc/wc/taxes/WCTaxStoreTest.kt | 22 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/TaxTestUtils.kt b/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/TaxTestUtils.kt index 1ec2985f46..b29d0354e8 100644 --- a/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/TaxTestUtils.kt +++ b/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/TaxTestUtils.kt @@ -2,6 +2,7 @@ package org.wordpress.android.fluxc.wc.taxes import org.wordpress.android.fluxc.model.taxes.WCTaxClassModel import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient.TaxClassApiResponse +import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient.TaxRateApiResponse object TaxTestUtils { private fun generateSampleTaxClass( @@ -31,4 +32,12 @@ object TaxTestUtils { return listOf(TaxClassApiResponse("example1", "example1"), TaxClassApiResponse("example2", "example2")) } + + fun generateSampleTaxRateApiResponse(): Array { + return arrayOf( + TaxRateApiResponse(1), + TaxRateApiResponse(2) + ) + } } + diff --git a/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt b/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt index d85483cce8..d948c45237 100644 --- a/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt +++ b/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt @@ -1,6 +1,7 @@ package org.wordpress.android.fluxc.wc.taxes import com.yarolegovich.wellsql.WellSql +import kotlinx.coroutines.runBlocking import org.assertj.core.api.Assertions.assertThat import org.junit.Before import org.junit.Test @@ -86,6 +87,27 @@ class WCTaxStoreTest { assertThat(invalidRequestResult.size).isEqualTo(0) } + @Test + fun`when fetch tax rate fails, then error is returned` () { + runBlocking { + val error = WooError(INVALID_RESPONSE, NETWORK_ERROR, "Invalid site ID") + whenever(restClient.fetchTaxRateList(site, 1, 100)).thenReturn(WooPayload(error)) + val result = store.fetchTaxRateList(site) + assertThat(result.error).isEqualTo(error) + } + } + + @Test + fun `when fetch tax rate succeeds, then success returns` () { + runBlocking { + val taxRateApiResponse = TaxTestUtils.generateSampleTaxRateApiResponse() + whenever(restClient.fetchTaxRateList(site, 1, 100)).thenReturn(WooPayload(taxRateApiResponse)) + val result = store.fetchTaxRateList(site) + assertThat(result.isError).isFalse + assertThat(result.result).isEqualTo(taxRateApiResponse) + } + } + private suspend fun fetchTaxClassListForSite(): WooResult> { val fetchTaxClassListPayload = WooPayload(sampleTaxClassList.toTypedArray()) whenever(restClient.fetchTaxClassList(site)).thenReturn(fetchTaxClassListPayload) From 1a11ff671b6e292c0b1d06c6eb219d9edb3c4b0f Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 6 Sep 2023 17:57:30 -0300 Subject: [PATCH 11/55] Adjust pageSize parameter to be configurable from WCGlobalAttributeStore --- .../wc/product/attributes/ProductAttributeRestClient.kt | 2 +- .../wordpress/android/fluxc/store/WCGlobalAttributeStore.kt | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/product/attributes/ProductAttributeRestClient.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/product/attributes/ProductAttributeRestClient.kt index 81279d6947..e33b8767f9 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/product/attributes/ProductAttributeRestClient.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/product/attributes/ProductAttributeRestClient.kt @@ -43,7 +43,7 @@ class ProductAttributeRestClient @Inject constructor(private val wooNetwork: Woo suspend fun fetchAllAttributeTerms( site: SiteModel, attributeID: Long, - pageSize: Int = 100 + pageSize: Int ) = WOOCOMMERCE.products.attributes.attribute(attributeID).terms.pathV3 .request>( site = site, diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCGlobalAttributeStore.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCGlobalAttributeStore.kt index 3c2f0dcf07..0359c89022 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCGlobalAttributeStore.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCGlobalAttributeStore.kt @@ -54,8 +54,9 @@ class WCGlobalAttributeStore @Inject constructor( suspend fun fetchAttributeTerms( site: SiteModel, - attributeID: Long - ) = restClient.fetchAllAttributeTerms(site, attributeID) + attributeID: Long, + pageSize: Int = 100 + ) = restClient.fetchAllAttributeTerms(site, attributeID, pageSize) .result?.map { mapper.responseToAttributeTermModel(it, attributeID.toInt(), site) } ?.apply { insertAttributeTermsFromScratch(attributeID.toInt(), site.id, this) From ca697a3b15508e22f4b7aaef5401c2bad49176c4 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Wed, 6 Sep 2023 17:04:59 -0400 Subject: [PATCH 12/55] Fix test --- .../org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt | 4 ++-- .../kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt b/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt index d948c45237..0d5826d0d3 100644 --- a/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt +++ b/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt @@ -92,7 +92,7 @@ class WCTaxStoreTest { runBlocking { val error = WooError(INVALID_RESPONSE, NETWORK_ERROR, "Invalid site ID") whenever(restClient.fetchTaxRateList(site, 1, 100)).thenReturn(WooPayload(error)) - val result = store.fetchTaxRateList(site) + val result = store.fetchTaxRateList(site, 1, 100) assertThat(result.error).isEqualTo(error) } } @@ -102,7 +102,7 @@ class WCTaxStoreTest { runBlocking { val taxRateApiResponse = TaxTestUtils.generateSampleTaxRateApiResponse() whenever(restClient.fetchTaxRateList(site, 1, 100)).thenReturn(WooPayload(taxRateApiResponse)) - val result = store.fetchTaxRateList(site) + val result = store.fetchTaxRateList(site, 1, 100) assertThat(result.isError).isFalse assertThat(result.result).isEqualTo(taxRateApiResponse) } diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt index 6ba198aed5..0f3bc3da39 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt @@ -49,7 +49,7 @@ class WCTaxStore @Inject constructor( } } } - suspend fun fetchTaxRateList(site: SiteModel): WooPayload> { - return restClient.fetchTaxRateList(site, 1, 100) + suspend fun fetchTaxRateList(site: SiteModel, page: Int, pageSize: Int): WooPayload> { + return restClient.fetchTaxRateList(site, page, pageSize) } } From 11d4832c25d51ec976ec2d1258440c98e33b1d9d Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Thu, 7 Sep 2023 08:48:43 +0100 Subject: [PATCH 13/55] Expose document mime types to client apps --- .../main/java/org/wordpress/android/fluxc/utils/MimeTypes.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/utils/MimeTypes.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/utils/MimeTypes.kt index a64215a0e9..7f70219eed 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/utils/MimeTypes.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/utils/MimeTypes.kt @@ -204,6 +204,9 @@ class MimeTypes { fun getAudioTypesOnly(plan: Plan = NO_PLAN_SPECIFIED) = (getAudioMimeTypesOnly(plan).toStrings()).toSet().toTypedArray() + fun getDocumentTypesOnly(plan: Plan = NO_PLAN_SPECIFIED) = + (getDocumentMimeTypesOnly(plan).toStrings()).toSet().toTypedArray() + private fun getAudioMimeTypesOnly(plan: Plan = NO_PLAN_SPECIFIED): List { return when (plan) { WP_COM_PAID, SELF_HOSTED, NO_PLAN_SPECIFIED -> audioTypes From f84e9ec543825ce11134b5049aa757bc711a44c3 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Thu, 7 Sep 2023 07:08:47 -0400 Subject: [PATCH 14/55] Fix store FetchTaxRate returning type --- .../android/fluxc/wc/taxes/WCTaxStoreTest.kt | 2 +- .../org/wordpress/android/fluxc/store/WCTaxStore.kt | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt b/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt index 0d5826d0d3..3b6b8edd07 100644 --- a/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt +++ b/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt @@ -104,7 +104,7 @@ class WCTaxStoreTest { whenever(restClient.fetchTaxRateList(site, 1, 100)).thenReturn(WooPayload(taxRateApiResponse)) val result = store.fetchTaxRateList(site, 1, 100) assertThat(result.isError).isFalse - assertThat(result.result).isEqualTo(taxRateApiResponse) + assertThat(result.model).isEqualTo(taxRateApiResponse.toList()) } } diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt index 0f3bc3da39..546efb87af 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt @@ -49,7 +49,16 @@ class WCTaxStore @Inject constructor( } } } - suspend fun fetchTaxRateList(site: SiteModel, page: Int, pageSize: Int): WooPayload> { - return restClient.fetchTaxRateList(site, page, pageSize) + suspend fun fetchTaxRateList( + site: SiteModel, + page: Int, + pageSize: Int + ): WooResult> { + val response = restClient.fetchTaxRateList(site, page, pageSize) + return when { + response.isError -> WooResult(response.error) + response.result != null -> WooResult(response.result.toList()) + else -> WooResult(WooError(GENERIC_ERROR, UNKNOWN)) + } } } From 42f42a55f4964e20dafeb7756e17b0189ba2683d Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Thu, 7 Sep 2023 07:09:38 -0400 Subject: [PATCH 15/55] Remove unused import --- .../main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt index 546efb87af..6ed33df33e 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt @@ -6,7 +6,6 @@ import org.wordpress.android.fluxc.model.taxes.WCTaxClassModel 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.network.rest.wpcom.wc.WooResult import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient.TaxRateApiResponse From d58b1d8d3f898c7b07b959836901f9a61869f9c6 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 7 Sep 2023 10:55:36 -0300 Subject: [PATCH 16/55] Add page parameter to Attribute list fetching --- .../wc/product/attributes/ProductAttributeRestClient.kt | 6 +++++- .../wordpress/android/fluxc/store/WCGlobalAttributeStore.kt | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/product/attributes/ProductAttributeRestClient.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/product/attributes/ProductAttributeRestClient.kt index e33b8767f9..38bb3f3d48 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/product/attributes/ProductAttributeRestClient.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/product/attributes/ProductAttributeRestClient.kt @@ -43,11 +43,15 @@ class ProductAttributeRestClient @Inject constructor(private val wooNetwork: Woo suspend fun fetchAllAttributeTerms( site: SiteModel, attributeID: Long, + page: Int, pageSize: Int ) = WOOCOMMERCE.products.attributes.attribute(attributeID).terms.pathV3 .request>( site = site, - params = mapOf("per_page" to pageSize.toString()) + params = mapOf( + "page" to page.toString(), + "per_page" to pageSize.toString() + ) ) suspend fun postNewTerm( diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCGlobalAttributeStore.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCGlobalAttributeStore.kt index 0359c89022..2a9718ea42 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCGlobalAttributeStore.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCGlobalAttributeStore.kt @@ -55,8 +55,9 @@ class WCGlobalAttributeStore @Inject constructor( suspend fun fetchAttributeTerms( site: SiteModel, attributeID: Long, + page: Int, pageSize: Int = 100 - ) = restClient.fetchAllAttributeTerms(site, attributeID, pageSize) + ) = restClient.fetchAllAttributeTerms(site, attributeID, page, pageSize) .result?.map { mapper.responseToAttributeTermModel(it, attributeID.toInt(), site) } ?.apply { insertAttributeTermsFromScratch(attributeID.toInt(), site.id, this) From f530c2e55998f409eef286b4ea50741d090045b1 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 7 Sep 2023 11:47:54 -0300 Subject: [PATCH 17/55] Adjust WCGlobalAttributeStore.fetchAttributeTerms to also use default value for page --- .../org/wordpress/android/fluxc/store/WCGlobalAttributeStore.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCGlobalAttributeStore.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCGlobalAttributeStore.kt index 2a9718ea42..2a91e4223d 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCGlobalAttributeStore.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCGlobalAttributeStore.kt @@ -55,7 +55,7 @@ class WCGlobalAttributeStore @Inject constructor( suspend fun fetchAttributeTerms( site: SiteModel, attributeID: Long, - page: Int, + page: Int = 1, pageSize: Int = 100 ) = restClient.fetchAllAttributeTerms(site, attributeID, page, pageSize) .result?.map { mapper.responseToAttributeTermModel(it, attributeID.toInt(), site) } From 79b2c1bb2190e11f622bd855bffe088fca774814 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Thu, 7 Sep 2023 11:34:18 -0400 Subject: [PATCH 18/55] Rename TaxRateModel --- .../android/fluxc/wc/taxes/TaxTestUtils.kt | 8 ++--- .../rest/wpcom/wc/taxes/WCTaxRestClient.kt | 31 ++++++++++--------- .../android/fluxc/store/WCTaxStore.kt | 4 +-- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/TaxTestUtils.kt b/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/TaxTestUtils.kt index b29d0354e8..aa3526e8f3 100644 --- a/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/TaxTestUtils.kt +++ b/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/TaxTestUtils.kt @@ -2,7 +2,7 @@ package org.wordpress.android.fluxc.wc.taxes import org.wordpress.android.fluxc.model.taxes.WCTaxClassModel import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient.TaxClassApiResponse -import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient.TaxRateApiResponse +import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient.TaxRateModel object TaxTestUtils { private fun generateSampleTaxClass( @@ -33,10 +33,10 @@ object TaxTestUtils { TaxClassApiResponse("example2", "example2")) } - fun generateSampleTaxRateApiResponse(): Array { + fun generateSampleTaxRateApiResponse(): Array { return arrayOf( - TaxRateApiResponse(1), - TaxRateApiResponse(2) + TaxRateModel(1), + TaxRateModel(2) ) } } diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/WCTaxRestClient.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/WCTaxRestClient.kt index b6f4308704..d39c13d10e 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/WCTaxRestClient.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/WCTaxRestClient.kt @@ -1,5 +1,6 @@ package org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes +import com.google.gson.annotations.SerializedName import org.wordpress.android.fluxc.generated.endpoint.WOOCOMMERCE import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.network.rest.wpapi.WPAPIResponse @@ -29,13 +30,13 @@ class WCTaxRestClient @Inject constructor(private val wooNetwork: WooNetwork) { site: SiteModel, page: Int, pageSize: Int, - ): WooPayload> { + ): WooPayload> { val url = WOOCOMMERCE.taxes.pathV3 val response = wooNetwork.executeGetGsonRequest( site, url, - Array::class.java, + Array::class.java, mutableMapOf().apply { put("page", page.toString()) put("per_page", pageSize.toString()) @@ -56,20 +57,20 @@ class WCTaxRestClient @Inject constructor(private val wooNetwork: WooNetwork) { val slug: String? = null ) - data class TaxRateApiResponse( + data class TaxRateModel( val id: Int, - val country: String = "", - val state: String = "", - val postcode: String = "", - val city: String = "", - val postCodes: List? = null, + val country: String? = null, + val state: String? = null, + val postcode: String? = null, + val city: String? = null, + @SerializedName("postcodes") val postCodes: List? = null, val cities: List? = null, - val rate: String = "", - val name: String = "", - val priority: Int = 0, - val compound: Boolean = false, - val shipping: Boolean = false, - val order: Int = 0, - val taxClass: String = "", + val rate: String? = null, + val name: String? = null, + val priority: Int? = null, + val compound: Boolean? = null, + val shipping: Boolean? = null, + val order: Int? = null, + @SerializedName("class") val taxClass: String? = null, ) } diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt index 6ed33df33e..d39693b0fb 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt @@ -8,7 +8,7 @@ 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.WooResult import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient -import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient.TaxRateApiResponse +import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient.TaxRateModel import org.wordpress.android.fluxc.persistence.WCTaxSqlUtils import org.wordpress.android.fluxc.tools.CoroutineEngine import org.wordpress.android.util.AppLog @@ -52,7 +52,7 @@ class WCTaxStore @Inject constructor( site: SiteModel, page: Int, pageSize: Int - ): WooResult> { + ): WooResult> { val response = restClient.fetchTaxRateList(site, page, pageSize) return when { response.isError -> WooResult(response.error) From 4627ca7c8f55fb6edb3cc1f88b1669dcaab77cff Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Thu, 7 Sep 2023 15:28:35 -0400 Subject: [PATCH 19/55] Add tests --- .../android/fluxc/wc/taxes/TaxTestUtils.kt | 11 +++---- .../android/fluxc/wc/taxes/WCTaxStoreTest.kt | 3 +- .../test/resources/wc/tax-rate-response.json | 33 +++++++++++++++++++ 3 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 example/src/test/resources/wc/tax-rate-response.json diff --git a/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/TaxTestUtils.kt b/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/TaxTestUtils.kt index aa3526e8f3..b321e60134 100644 --- a/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/TaxTestUtils.kt +++ b/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/TaxTestUtils.kt @@ -1,6 +1,8 @@ package org.wordpress.android.fluxc.wc.taxes +import org.wordpress.android.fluxc.JsonLoaderUtils.jsonFileAs import org.wordpress.android.fluxc.model.taxes.WCTaxClassModel +import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient.TaxClassApiResponse import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient.TaxRateModel @@ -33,11 +35,8 @@ object TaxTestUtils { TaxClassApiResponse("example2", "example2")) } - fun generateSampleTaxRateApiResponse(): Array { - return arrayOf( - TaxRateModel(1), - TaxRateModel(2) - ) - } + fun generateSampleTaxRateApiResponse() = + "wc/tax-rate-response.json" + .jsonFileAs(Array::class.java) } diff --git a/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt b/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt index 3b6b8edd07..755f85a049 100644 --- a/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt +++ b/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt @@ -103,8 +103,9 @@ class WCTaxStoreTest { val taxRateApiResponse = TaxTestUtils.generateSampleTaxRateApiResponse() whenever(restClient.fetchTaxRateList(site, 1, 100)).thenReturn(WooPayload(taxRateApiResponse)) val result = store.fetchTaxRateList(site, 1, 100) + assertThat(this).isNotNull assertThat(result.isError).isFalse - assertThat(result.model).isEqualTo(taxRateApiResponse.toList()) + assertThat(result.model).isEqualTo(taxRateApiResponse?.toList()) } } diff --git a/example/src/test/resources/wc/tax-rate-response.json b/example/src/test/resources/wc/tax-rate-response.json new file mode 100644 index 0000000000..f83193043c --- /dev/null +++ b/example/src/test/resources/wc/tax-rate-response.json @@ -0,0 +1,33 @@ +[{ + "id":1, + "country":"US", + "state":"GA", + "postcode":"31707", + "city":"ALBANY", + "rate":"10.0000", + "name":"Superlong taaaaaaaax nameeeeee", + "priority":1, + "compound":false, + "shipping":true, + "order":0, + "class":"standard", + "postcodes":[ + "31707" + ], + "cities":[ + "ALBANY" + ], + "_links":{ + "self":[ + { + "href":"https://testwoomobile.wpcomstaging.com/wp-json/wc/v3/taxes/1" + } + ], + "collection":[ + { + "href":"https://testwoomobile.wpcomstaging.com/wp-json/wc/v3/taxes" + } + ] + } + } +] \ No newline at end of file From 3f3cacdcd0683531b97b4366681a30cf46164f45 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Thu, 7 Sep 2023 15:29:34 -0400 Subject: [PATCH 20/55] Remove unused imports --- .../java/org/wordpress/android/fluxc/wc/taxes/TaxTestUtils.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/TaxTestUtils.kt b/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/TaxTestUtils.kt index b321e60134..f0ad2cf1ca 100644 --- a/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/TaxTestUtils.kt +++ b/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/TaxTestUtils.kt @@ -2,7 +2,6 @@ package org.wordpress.android.fluxc.wc.taxes import org.wordpress.android.fluxc.JsonLoaderUtils.jsonFileAs import org.wordpress.android.fluxc.model.taxes.WCTaxClassModel -import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient.TaxClassApiResponse import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient.TaxRateModel From c1c3ecf6548866e07def15d7e60d1bbf1ca54a80 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Mon, 11 Sep 2023 16:56:43 -0400 Subject: [PATCH 21/55] Add TaxRateDao --- .../fluxc/persistence/dao/TaxRateDao.kt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt new file mode 100644 index 0000000000..384045a0fa --- /dev/null +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt @@ -0,0 +1,19 @@ +package org.wordpress.android.fluxc.persistence.dao + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import org.wordpress.android.fluxc.model.taxes.TaxRateEntity + +@Dao +interface TaxRateDao { + @Query("SELECT * FROM TaxRate WHERE localSiteId = :localSiteId") + suspend fun getTaxRates(localSiteId: Long): List + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertOrUpdate(taxRate: TaxRateEntity): Long + + @Query("DELETE FROM TaxRate WHERE localSiteId = :localSiteId") + suspend fun deleteAll(localSiteId: Long) +} From f48c3ee3b3153ebda49b774fb7b45382703aa978 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Mon, 11 Sep 2023 16:56:55 -0400 Subject: [PATCH 22/55] Add TaxRateEntity --- .../android/fluxc/model/taxes/TaxRateEntity.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt new file mode 100644 index 0000000000..180d94d79e --- /dev/null +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt @@ -0,0 +1,15 @@ +package org.wordpress.android.fluxc.model.taxes + +import androidx.room.Entity +import androidx.room.PrimaryKey +import org.wordpress.android.fluxc.model.LocalOrRemoteId.LocalId +import org.wordpress.android.fluxc.model.LocalOrRemoteId.RemoteId + +@Entity( + tableName = "TaxRate", + primaryKeys = ["id", "localSiteId"], + ) +data class TaxRateEntity ( + val id: RemoteId, + val localSiteId: LocalId, +) From cde43cf60ed4d96edf9fa59801ef6e997c205104 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Mon, 11 Sep 2023 16:57:47 -0400 Subject: [PATCH 23/55] Bump Database Version --- .../org/wordpress/android/fluxc/di/WCDatabaseModule.kt | 2 ++ .../android/fluxc/persistence/WCAndroidDatabase.kt | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/di/WCDatabaseModule.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/di/WCDatabaseModule.kt index f2f6b4d55a..84258603a9 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/di/WCDatabaseModule.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/di/WCDatabaseModule.kt @@ -44,6 +44,8 @@ interface WCDatabaseModule { @Provides fun provideTopPerformerProductsDao(database: WCAndroidDatabase) = database.topPerformerProductsDao @Provides fun provideTaxBasedOnDao(database: WCAndroidDatabase) = database.taxBasedOnSettingDao + + @Provides fun provideTaxRateDao(database: WCAndroidDatabase) = database.taxRateDao } @Binds fun bindTransactionExecutor(database: WCAndroidDatabase): TransactionExecutor } diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt index 8061b85dcd..ae1f26aef2 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt @@ -9,6 +9,7 @@ import androidx.room.TypeConverters import androidx.room.withTransaction import org.wordpress.android.fluxc.model.OrderEntity import org.wordpress.android.fluxc.model.taxes.TaxBasedOnSettingEntity +import org.wordpress.android.fluxc.model.taxes.TaxRateEntity import org.wordpress.android.fluxc.persistence.converters.BigDecimalConverter import org.wordpress.android.fluxc.persistence.converters.LocalIdConverter import org.wordpress.android.fluxc.persistence.converters.LongListConverter @@ -20,6 +21,7 @@ import org.wordpress.android.fluxc.persistence.dao.OrderMetaDataDao import org.wordpress.android.fluxc.persistence.dao.OrderNotesDao import org.wordpress.android.fluxc.persistence.dao.OrdersDao import org.wordpress.android.fluxc.persistence.dao.TaxBasedOnDao +import org.wordpress.android.fluxc.persistence.dao.TaxRateDao import org.wordpress.android.fluxc.persistence.dao.TopPerformerProductsDao import org.wordpress.android.fluxc.persistence.entity.AddonEntity import org.wordpress.android.fluxc.persistence.entity.AddonOptionEntity @@ -54,7 +56,7 @@ import org.wordpress.android.fluxc.persistence.migrations.MIGRATION_8_9 import org.wordpress.android.fluxc.persistence.migrations.MIGRATION_9_10 @Database( - version = 26, + version = 27, entities = [ AddonEntity::class, AddonOptionEntity::class, @@ -68,6 +70,7 @@ import org.wordpress.android.fluxc.persistence.migrations.MIGRATION_9_10 InboxNoteActionEntity::class, TopPerformerProductEntity::class, TaxBasedOnSettingEntity::class, + TaxRateEntity::class ], autoMigrations = [ AutoMigration(from = 12, to = 13), @@ -79,6 +82,7 @@ import org.wordpress.android.fluxc.persistence.migrations.MIGRATION_9_10 AutoMigration(from = 19, to = 20, spec = AutoMigration19to20::class), AutoMigration(from = 23, to = 24, spec = AutoMigration23to24::class), AutoMigration(from = 25, to = 26), + AutoMigration(from = 26, to = 27), ] ) @TypeConverters( @@ -98,6 +102,7 @@ abstract class WCAndroidDatabase : RoomDatabase(), TransactionExecutor { abstract val inboxNotesDao: InboxNotesDao abstract val topPerformerProductsDao: TopPerformerProductsDao abstract val taxBasedOnSettingDao: TaxBasedOnDao + abstract val taxRateDao: TaxRateDao companion object { fun buildDb(applicationContext: Context) = Room.databaseBuilder( From a362c4e5288d3aa0543907e79b42e9a861e809f4 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Mon, 11 Sep 2023 16:58:42 -0400 Subject: [PATCH 24/55] Remove unused import --- .../org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt index 180d94d79e..0db9293003 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt @@ -1,7 +1,6 @@ package org.wordpress.android.fluxc.model.taxes import androidx.room.Entity -import androidx.room.PrimaryKey import org.wordpress.android.fluxc.model.LocalOrRemoteId.LocalId import org.wordpress.android.fluxc.model.LocalOrRemoteId.RemoteId From a5d93cd9e896a1c61fdba71ba5c7ce3c827af6de Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Tue, 12 Sep 2023 13:19:04 -0400 Subject: [PATCH 25/55] Bump Database Version - generated json --- .../27.json | 1280 +++++++++++++++++ 1 file changed, 1280 insertions(+) create mode 100644 plugins/woocommerce/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/27.json diff --git a/plugins/woocommerce/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/27.json b/plugins/woocommerce/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/27.json new file mode 100644 index 0000000000..399fd90ccf --- /dev/null +++ b/plugins/woocommerce/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/27.json @@ -0,0 +1,1280 @@ +{ + "formatVersion": 1, + "database": { + "version": 27, + "identityHash": "f2c454ea3a1d74cf4b7ec999502708bc", + "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", + "notNull": false + }, + { + "fieldPath": "productRemoteId", + "columnName": "productRemoteId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "display", + "columnName": "display", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "titleFormat", + "columnName": "titleFormat", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "required", + "columnName": "required", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "position", + "columnName": "position", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "restrictions", + "columnName": "restrictions", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "priceType", + "columnName": "priceType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "min", + "columnName": "min", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "max", + "columnName": "max", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "addonLocalId" + ], + "autoGenerate": true + }, + "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", + "notNull": false + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "image", + "columnName": "image", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "addonOptionLocalId" + ], + "autoGenerate": true + }, + "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", + "notNull": false + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "dateCreatedGmt", + "columnName": "dateCreatedGmt", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "dateModified", + "columnName": "dateModified", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "dateModifiedGmt", + "columnName": "dateModifiedGmt", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "discountType", + "columnName": "discountType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "dateExpires", + "columnName": "dateExpires", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "dateExpiresGmt", + "columnName": "dateExpiresGmt", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "usageCount", + "columnName": "usageCount", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "isForIndividualUse", + "columnName": "isForIndividualUse", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "usageLimit", + "columnName": "usageLimit", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "usageLimitPerUser", + "columnName": "usageLimitPerUser", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "limitUsageToXItems", + "columnName": "limitUsageToXItems", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "isShippingFree", + "columnName": "isShippingFree", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "areSaleItemsExcluded", + "columnName": "areSaleItemsExcluded", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "minimumAmount", + "columnName": "minimumAmount", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "maximumAmount", + "columnName": "maximumAmount", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "includedProductIds", + "columnName": "includedProductIds", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "excludedProductIds", + "columnName": "excludedProductIds", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "includedCategoryIds", + "columnName": "includedCategoryIds", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "excludedCategoryIds", + "columnName": "excludedCategoryIds", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id", + "localSiteId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "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": { + "columnNames": [ + "couponId", + "localSiteId", + "email" + ], + "autoGenerate": false + }, + "indices": [], + "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": { + "columnNames": [ + "globalGroupLocalId" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "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", + "notNull": false + }, + { + "fieldPath": "note", + "columnName": "note", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "author", + "columnName": "author", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isSystemNote", + "columnName": "isSystemNote", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isCustomerNote", + "columnName": "isCustomerNote", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "localSiteId", + "noteId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "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, `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, 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": "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" + } + ], + "primaryKey": { + "columnNames": [ + "localSiteId", + "orderId" + ], + "autoGenerate": false + }, + "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`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "OrderMetaData", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `orderId` INTEGER NOT NULL, `key` TEXT NOT NULL, `value` TEXT NOT NULL, `isDisplayable` INTEGER NOT NULL DEFAULT 1, PRIMARY KEY(`localSiteId`, `orderId`, `id`), FOREIGN KEY(`localSiteId`, `orderId`) REFERENCES `OrderEntity`(`localSiteId`, `orderId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "orderId", + "columnName": "orderId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isDisplayable", + "columnName": "isDisplayable", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "1" + } + ], + "primaryKey": { + "columnNames": [ + "localSiteId", + "orderId", + "id" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_OrderMetaData_localSiteId_orderId", + "unique": false, + "columnNames": [ + "localSiteId", + "orderId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_OrderMetaData_localSiteId_orderId` ON `${TABLE_NAME}` (`localSiteId`, `orderId`)" + } + ], + "foreignKeys": [ + { + "table": "OrderEntity", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "localSiteId", + "orderId" + ], + "referencedColumns": [ + "localSiteId", + "orderId" + ] + } + ] + }, + { + "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", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "dateReminder", + "columnName": "dateReminder", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "localId" + ], + "autoGenerate": true + }, + "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`)" + } + ], + "foreignKeys": [] + }, + { + "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", + "notNull": false + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "primary", + "columnName": "primary", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "actionedText", + "columnName": "actionedText", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "remoteId", + "inboxNoteLocalId" + ], + "autoGenerate": false + }, + "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", + "notNull": false + }, + { + "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": { + "columnNames": [ + "datePeriod", + "productId", + "localSiteId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "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": { + "columnNames": [ + "localSiteId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "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", + "notNull": false + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "postcode", + "columnName": "postcode", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "city", + "columnName": "city", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "rate", + "columnName": "rate", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "taxClass", + "columnName": "taxClass", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id", + "localSiteId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "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, 'f2c454ea3a1d74cf4b7ec999502708bc')" + ] + } +} \ No newline at end of file From 6490452c0ba33ba0a110a344dc39a516f75c1941 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Tue, 12 Sep 2023 13:19:32 -0400 Subject: [PATCH 26/55] Create Dto file --- .../network/rest/wpcom/wc/taxes/TaxRateDto.kt | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/TaxRateDto.kt diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/TaxRateDto.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/TaxRateDto.kt new file mode 100644 index 0000000000..bb7e1c725a --- /dev/null +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/TaxRateDto.kt @@ -0,0 +1,38 @@ +package org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes + +import com.google.gson.annotations.SerializedName +import org.wordpress.android.fluxc.model.LocalOrRemoteId.LocalId +import org.wordpress.android.fluxc.model.LocalOrRemoteId.RemoteId +import org.wordpress.android.fluxc.model.taxes.TaxRateEntity + +data class TaxRateDto ( + @SerializedName("id") val id: Long, + @SerializedName("country") val country: String?, + @SerializedName("state" )val state: String?, + @SerializedName("postcode") val postCode: String?, + @SerializedName("city") val city: String?, + @SerializedName("postcodes") val postCodes: List?, + @SerializedName("cities") val cities: List?, + @SerializedName("rate") val rate: String?, + @SerializedName("name") val name: String?, + @SerializedName("priority") val priority: Int?, + @SerializedName("compound") val compound: Boolean?, + @SerializedName("shipping") val shipping: Boolean?, + @SerializedName("order") val order: Int?, + @SerializedName("class") val taxClass: String?, +) { + fun toDataModel(localSiteId: LocalId): TaxRateEntity = + TaxRateEntity( + id = RemoteId(id), + localSiteId = localSiteId, + country = country, + state = state, + postcode = postCode, + city = city, + rate = rate, + name = name, + taxClass = taxClass, + ) +} + + From 3767490eff2db07ba8104df9a46990b4a8150a7b Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Tue, 12 Sep 2023 13:20:17 -0400 Subject: [PATCH 27/55] Update props in the entity --- .../wordpress/android/fluxc/model/taxes/TaxRateEntity.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt index 0db9293003..caa0db28c9 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt @@ -11,4 +11,11 @@ import org.wordpress.android.fluxc.model.LocalOrRemoteId.RemoteId data class TaxRateEntity ( val id: RemoteId, val localSiteId: LocalId, + val country: String? = null, + val state: String? = null, + val postcode: String? = null, + val city: String? = null, + val rate: String? = null, + val name: String? = null, + val taxClass: String? = null, ) From 6fd65d978795bfad522005587350d57021ae338e Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Tue, 12 Sep 2023 13:20:46 -0400 Subject: [PATCH 28/55] Move away from dataModel naming and replace it with Dto --- .../rest/wpcom/wc/taxes/WCTaxRestClient.kt | 22 ++----------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/WCTaxRestClient.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/WCTaxRestClient.kt index d39c13d10e..99994b6169 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/WCTaxRestClient.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/WCTaxRestClient.kt @@ -1,6 +1,5 @@ package org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes -import com.google.gson.annotations.SerializedName import org.wordpress.android.fluxc.generated.endpoint.WOOCOMMERCE import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.network.rest.wpapi.WPAPIResponse @@ -30,13 +29,13 @@ class WCTaxRestClient @Inject constructor(private val wooNetwork: WooNetwork) { site: SiteModel, page: Int, pageSize: Int, - ): WooPayload> { + ): WooPayload> { val url = WOOCOMMERCE.taxes.pathV3 val response = wooNetwork.executeGetGsonRequest( site, url, - Array::class.java, + Array::class.java, mutableMapOf().apply { put("page", page.toString()) put("per_page", pageSize.toString()) @@ -56,21 +55,4 @@ class WCTaxRestClient @Inject constructor(private val wooNetwork: WooNetwork) { val name: String? = null, val slug: String? = null ) - - data class TaxRateModel( - val id: Int, - val country: String? = null, - val state: String? = null, - val postcode: String? = null, - val city: String? = null, - @SerializedName("postcodes") val postCodes: List? = null, - val cities: List? = null, - val rate: String? = null, - val name: String? = null, - val priority: Int? = null, - val compound: Boolean? = null, - val shipping: Boolean? = null, - val order: Int? = null, - @SerializedName("class") val taxClass: String? = null, - ) } From 5ba195e0531f4b1728b6a9d27aeb9e2500b1db9d Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Tue, 12 Sep 2023 13:21:24 -0400 Subject: [PATCH 29/55] Add reference to Dto and get single tax method --- .../org/wordpress/android/fluxc/store/WCTaxStore.kt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt index d39693b0fb..de7c80449d 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt @@ -1,5 +1,6 @@ package org.wordpress.android.fluxc.store +import org.wordpress.android.fluxc.model.LocalOrRemoteId.RemoteId import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.model.taxes.WCTaxClassMapper import org.wordpress.android.fluxc.model.taxes.WCTaxClassModel @@ -7,9 +8,10 @@ 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.WooResult +import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.TaxRateDto import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient -import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient.TaxRateModel import org.wordpress.android.fluxc.persistence.WCTaxSqlUtils +import org.wordpress.android.fluxc.persistence.dao.TaxRateDao import org.wordpress.android.fluxc.tools.CoroutineEngine import org.wordpress.android.util.AppLog import javax.inject.Inject @@ -19,7 +21,8 @@ import javax.inject.Singleton class WCTaxStore @Inject constructor( private val restClient: WCTaxRestClient, private val coroutineEngine: CoroutineEngine, - private val mapper: WCTaxClassMapper + private val mapper: WCTaxClassMapper, + private val taxRateDao: TaxRateDao ) { /** * returns a list of tax classes for a specific site in the database @@ -52,7 +55,7 @@ class WCTaxStore @Inject constructor( site: SiteModel, page: Int, pageSize: Int - ): WooResult> { + ): WooResult> { val response = restClient.fetchTaxRateList(site, page, pageSize) return when { response.isError -> WooResult(response.error) @@ -60,4 +63,7 @@ class WCTaxStore @Inject constructor( else -> WooResult(WooError(GENERIC_ERROR, UNKNOWN)) } } + + suspend fun getTaxRate(site: SiteModel, taxRateId: Long) = + taxRateDao.getTaxRate(site.localId(), RemoteId(taxRateId)) } From d66e79c6a692d3d96197dd0ca644813c41248531 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Tue, 12 Sep 2023 13:22:01 -0400 Subject: [PATCH 30/55] Add get single tax method to dao --- .../android/fluxc/persistence/dao/TaxRateDao.kt | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt index 384045a0fa..073aa25a4e 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt @@ -4,16 +4,23 @@ import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query +import androidx.room.Transaction +import org.wordpress.android.fluxc.model.LocalOrRemoteId.LocalId +import org.wordpress.android.fluxc.model.LocalOrRemoteId.RemoteId import org.wordpress.android.fluxc.model.taxes.TaxRateEntity @Dao interface TaxRateDao { @Query("SELECT * FROM TaxRate WHERE localSiteId = :localSiteId") - suspend fun getTaxRates(localSiteId: Long): List + suspend fun getTaxRates(localSiteId: LocalId): List @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insertOrUpdate(taxRate: TaxRateEntity): Long @Query("DELETE FROM TaxRate WHERE localSiteId = :localSiteId") - suspend fun deleteAll(localSiteId: Long) + suspend fun deleteAll(localSiteId: LocalId) + + @Transaction + @Query("SELECT * FROM TaxRate WHERE localSiteId = :localSiteId AND id IN (:taxRateId)") + suspend fun getTaxRate(localSiteId: LocalId, taxRateId: RemoteId): TaxRateEntity? } From 6ebf7ee1c19cbd110dcfe1659555bd145b72be88 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Tue, 12 Sep 2023 13:32:17 -0400 Subject: [PATCH 31/55] Replace TaxRateModel with TaxRateDto in TaxTestUtils.kt --- .../java/org/wordpress/android/fluxc/wc/taxes/TaxTestUtils.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/TaxTestUtils.kt b/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/TaxTestUtils.kt index f0ad2cf1ca..ecd4c50c49 100644 --- a/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/TaxTestUtils.kt +++ b/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/TaxTestUtils.kt @@ -2,8 +2,8 @@ package org.wordpress.android.fluxc.wc.taxes import org.wordpress.android.fluxc.JsonLoaderUtils.jsonFileAs import org.wordpress.android.fluxc.model.taxes.WCTaxClassModel +import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.TaxRateDto import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient.TaxClassApiResponse -import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient.TaxRateModel object TaxTestUtils { private fun generateSampleTaxClass( @@ -36,6 +36,6 @@ object TaxTestUtils { fun generateSampleTaxRateApiResponse() = "wc/tax-rate-response.json" - .jsonFileAs(Array::class.java) + .jsonFileAs(Array::class.java) } From 34ccc7bd470911069e69f134593c3994daa7c6d0 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Tue, 12 Sep 2023 13:35:38 -0400 Subject: [PATCH 32/55] Fix tests --- .../org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt b/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt index 755f85a049..2729121960 100644 --- a/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt +++ b/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt @@ -23,6 +23,7 @@ import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooResult import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient import org.wordpress.android.fluxc.persistence.SiteSqlUtils import org.wordpress.android.fluxc.persistence.WellSqlConfig +import org.wordpress.android.fluxc.persistence.dao.TaxRateDao import org.wordpress.android.fluxc.store.WCTaxStore import org.wordpress.android.fluxc.test import org.wordpress.android.fluxc.tools.initCoroutineEngine @@ -35,6 +36,7 @@ class WCTaxStoreTest { private val errorSite = SiteModel().apply { id = 123 } private val mapper = WCTaxClassMapper() private lateinit var store: WCTaxStore + private val taxClassDao = mock() private val sampleTaxClassList = TaxTestUtils.generateSampleTaxClassApiResponse() private val error = WooError(INVALID_RESPONSE, NETWORK_ERROR, "Invalid site ID") @@ -53,7 +55,8 @@ class WCTaxStoreTest { store = WCTaxStore( restClient, initCoroutineEngine(), - mapper + mapper, + taxClassDao ) // Insert the site into the db so it's available later when fetching tax classes From 9d16fb77e4f869d972d48599ba7b95b808fa7df0 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Wed, 13 Sep 2023 07:43:37 -0400 Subject: [PATCH 33/55] Fix getTaxRate --- .../org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt index 073aa25a4e..47cb832503 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt @@ -8,6 +8,7 @@ import androidx.room.Transaction import org.wordpress.android.fluxc.model.LocalOrRemoteId.LocalId import org.wordpress.android.fluxc.model.LocalOrRemoteId.RemoteId import org.wordpress.android.fluxc.model.taxes.TaxRateEntity +import org.wordpress.android.fluxc.persistence.entity.CouponWithEmails @Dao interface TaxRateDao { @@ -21,6 +22,6 @@ interface TaxRateDao { suspend fun deleteAll(localSiteId: LocalId) @Transaction - @Query("SELECT * FROM TaxRate WHERE localSiteId = :localSiteId AND id IN (:taxRateId)") + @Query("SELECT * FROM TaxRate WHERE localSiteId = :localSiteId AND id = :taxRateId") suspend fun getTaxRate(localSiteId: LocalId, taxRateId: RemoteId): TaxRateEntity? } From f8eb534dddc6804b536cf26ac4065a19aea45ad5 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Wed, 13 Sep 2023 08:37:56 -0400 Subject: [PATCH 34/55] Add MigrationTest --- .../wordpress/android/fluxc/persistence/MigrationTests.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plugins/woocommerce/src/androidTest/java/org/wordpress/android/fluxc/persistence/MigrationTests.kt b/plugins/woocommerce/src/androidTest/java/org/wordpress/android/fluxc/persistence/MigrationTests.kt index c272e8abf3..c152af133d 100644 --- a/plugins/woocommerce/src/androidTest/java/org/wordpress/android/fluxc/persistence/MigrationTests.kt +++ b/plugins/woocommerce/src/androidTest/java/org/wordpress/android/fluxc/persistence/MigrationTests.kt @@ -227,6 +227,14 @@ class MigrationTests { } } + @Test + fun testMigrate26to27() { + helper.apply { + createDatabase(TEST_DB, 26).close() + runMigrationsAndValidate(TEST_DB, 27, false) + } + } + companion object { private const val TEST_DB = "migration-test" } From e1758cc82e90b81d0f18622f48d06b5511edb5dc Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Wed, 13 Sep 2023 09:34:40 -0400 Subject: [PATCH 35/55] Remove unused imports --- .../org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt index 47cb832503..a28476c6c1 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt @@ -8,7 +8,6 @@ import androidx.room.Transaction import org.wordpress.android.fluxc.model.LocalOrRemoteId.LocalId import org.wordpress.android.fluxc.model.LocalOrRemoteId.RemoteId import org.wordpress.android.fluxc.model.taxes.TaxRateEntity -import org.wordpress.android.fluxc.persistence.entity.CouponWithEmails @Dao interface TaxRateDao { From 8ebb591cf672537310e29c1893826872f0de27da Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Wed, 13 Sep 2023 12:02:42 -0400 Subject: [PATCH 36/55] Add insertorupdate method --- .../android/fluxc/store/WCTaxStore.kt | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt index de7c80449d..5197bf0a6c 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt @@ -22,13 +22,13 @@ class WCTaxStore @Inject constructor( private val restClient: WCTaxRestClient, private val coroutineEngine: CoroutineEngine, private val mapper: WCTaxClassMapper, - private val taxRateDao: TaxRateDao + private val taxRateDao: TaxRateDao, ) { /** * returns a list of tax classes for a specific site in the database */ fun getTaxClassListForSite(site: SiteModel): List = - WCTaxSqlUtils.getTaxClassesForSite(site.id) + WCTaxSqlUtils.getTaxClassesForSite(site.id) suspend fun fetchTaxClassList(site: SiteModel): WooResult> { return coroutineEngine.withDefaultContext(AppLog.T.API, this, "fetchTaxClassList") { @@ -37,6 +37,7 @@ class WCTaxStore @Inject constructor( response.isError -> { WooResult(response.error) } + response.result != null -> { val taxClassModels = response.result.map { mapper.map(it).apply { localSiteId = site.id } @@ -47,10 +48,12 @@ class WCTaxStore @Inject constructor( WCTaxSqlUtils.insertOrUpdateTaxClasses(taxClassModels) WooResult(taxClassModels) } + else -> WooResult(WooError(GENERIC_ERROR, UNKNOWN)) } } } + suspend fun fetchTaxRateList( site: SiteModel, page: Int, @@ -59,11 +62,22 @@ class WCTaxStore @Inject constructor( val response = restClient.fetchTaxRateList(site, page, pageSize) return when { response.isError -> WooResult(response.error) - response.result != null -> WooResult(response.result.toList()) + response.result != null -> { + if (page == 1) { + taxRateDao.deleteAll(site.localId()) + response.result.forEach { insertTaxRateToDatabase(it, site) } + } + WooResult(response.result.toList()) + } + else -> WooResult(WooError(GENERIC_ERROR, UNKNOWN)) } } + suspend fun insertTaxRateToDatabase(dto: TaxRateDto, site: SiteModel) { + taxRateDao.insertOrUpdate(dto.toDataModel(site.localId())) + } + suspend fun getTaxRate(site: SiteModel, taxRateId: Long) = - taxRateDao.getTaxRate(site.localId(), RemoteId(taxRateId)) + taxRateDao.getTaxRate(site.localId(), RemoteId(taxRateId)) } From 677602a74a6023b601632fff543c91f1fe42d9ec Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Wed, 13 Sep 2023 15:10:58 -0400 Subject: [PATCH 37/55] Update FetchTaxRates --- .../fluxc/persistence/dao/TaxRateDao.kt | 5 ++ .../android/fluxc/store/WCTaxStore.kt | 46 +++++++++++++------ 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt index a28476c6c1..45aa43dbd3 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt @@ -5,12 +5,17 @@ import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query import androidx.room.Transaction +import kotlinx.coroutines.flow.Flow import org.wordpress.android.fluxc.model.LocalOrRemoteId.LocalId import org.wordpress.android.fluxc.model.LocalOrRemoteId.RemoteId import org.wordpress.android.fluxc.model.taxes.TaxRateEntity @Dao interface TaxRateDao { + @Transaction + @Query("SELECT * FROM TaxRate WHERE localSiteId = :localSiteId") + fun observeTaxRates(localSiteId: LocalId): Flow> + @Query("SELECT * FROM TaxRate WHERE localSiteId = :localSiteId") suspend fun getTaxRates(localSiteId: LocalId): List diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt index 5197bf0a6c..53ba338005 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt @@ -1,7 +1,11 @@ package org.wordpress.android.fluxc.store +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.distinctUntilChanged import org.wordpress.android.fluxc.model.LocalOrRemoteId.RemoteId import org.wordpress.android.fluxc.model.SiteModel +import org.wordpress.android.fluxc.model.taxes.TaxRateEntity import org.wordpress.android.fluxc.model.taxes.WCTaxClassMapper import org.wordpress.android.fluxc.model.taxes.WCTaxClassModel import org.wordpress.android.fluxc.network.BaseRequest.GenericErrorType.UNKNOWN @@ -24,6 +28,12 @@ class WCTaxStore @Inject constructor( private val mapper: WCTaxClassMapper, private val taxRateDao: TaxRateDao, ) { + companion object { + // Just get everything + const val DEFAULT_PAGE_SIZE = 100 + const val DEFAULT_PAGE = 1 + } + /** * returns a list of tax classes for a specific site in the database */ @@ -54,27 +64,35 @@ class WCTaxStore @Inject constructor( } } + // Returns a boolean indicating whether more Tax Rates can be fetched suspend fun fetchTaxRateList( site: SiteModel, - page: Int, - pageSize: Int - ): WooResult> { - val response = restClient.fetchTaxRateList(site, page, pageSize) - return when { - response.isError -> WooResult(response.error) - response.result != null -> { - if (page == 1) { - taxRateDao.deleteAll(site.localId()) - response.result.forEach { insertTaxRateToDatabase(it, site) } + page: Int = DEFAULT_PAGE, + pageSize: Int = DEFAULT_PAGE_SIZE + ): WooResult { + return coroutineEngine.withDefaultContext(AppLog.T.API, this, "fetchTaxRateList") { + val response = restClient.fetchTaxRateList(site, page, pageSize) + when { + response.isError -> WooResult(response.error) + response.result != null -> { + if (page == 1) { + taxRateDao.deleteAll(site.localId()) + response.result.forEach { insertTaxRateToDatabase(it, site) } + } + val canLoadMore = response.result.size == pageSize + WooResult(canLoadMore) } - WooResult(response.result.toList()) - } - else -> WooResult(WooError(GENERIC_ERROR, UNKNOWN)) + else -> WooResult(WooError(GENERIC_ERROR, UNKNOWN)) + } } } - suspend fun insertTaxRateToDatabase(dto: TaxRateDto, site: SiteModel) { + @ExperimentalCoroutinesApi + fun observeTaxRates(site: SiteModel): Flow> = + taxRateDao.observeTaxRates(site.localId()).distinctUntilChanged() + + private suspend fun insertTaxRateToDatabase(dto: TaxRateDto, site: SiteModel) { taxRateDao.insertOrUpdate(dto.toDataModel(site.localId())) } From f1ccd7a6585e0baf9f7108615a0db07b8c341b46 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Wed, 13 Sep 2023 17:16:06 -0400 Subject: [PATCH 38/55] Update FetchTaxRates --- .../wordpress/android/fluxc/store/WCTaxStore.kt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt index 53ba338005..703cad167f 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt @@ -14,6 +14,7 @@ import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooErrorType.GENERIC_ER import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooResult import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.TaxRateDto import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient +import org.wordpress.android.fluxc.persistence.TransactionExecutor import org.wordpress.android.fluxc.persistence.WCTaxSqlUtils import org.wordpress.android.fluxc.persistence.dao.TaxRateDao import org.wordpress.android.fluxc.tools.CoroutineEngine @@ -27,6 +28,7 @@ class WCTaxStore @Inject constructor( private val coroutineEngine: CoroutineEngine, private val mapper: WCTaxClassMapper, private val taxRateDao: TaxRateDao, + private val database: TransactionExecutor ) { companion object { // Just get everything @@ -75,12 +77,14 @@ class WCTaxStore @Inject constructor( when { response.isError -> WooResult(response.error) response.result != null -> { - if (page == 1) { - taxRateDao.deleteAll(site.localId()) - response.result.forEach { insertTaxRateToDatabase(it, site) } + database.executeInTransaction { + if (page == 1) { + taxRateDao.deleteAll(site.localId()) + response.result.forEach { insertTaxRateToDatabase(it, site) } + } + val canLoadMore = response.result.size == pageSize + WooResult(canLoadMore) } - val canLoadMore = response.result.size == pageSize - WooResult(canLoadMore) } else -> WooResult(WooError(GENERIC_ERROR, UNKNOWN)) From d78989bf8a30215a8e1d411e43f9d4180535813b Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Wed, 13 Sep 2023 18:11:33 -0400 Subject: [PATCH 39/55] Fix tests --- .../org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt | 6 +++--- .../kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt | 4 ---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt b/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt index 2729121960..8883cf8055 100644 --- a/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt +++ b/example/src/test/java/org/wordpress/android/fluxc/wc/taxes/WCTaxStoreTest.kt @@ -36,7 +36,7 @@ class WCTaxStoreTest { private val errorSite = SiteModel().apply { id = 123 } private val mapper = WCTaxClassMapper() private lateinit var store: WCTaxStore - private val taxClassDao = mock() + private val taxRateDao = mock() private val sampleTaxClassList = TaxTestUtils.generateSampleTaxClassApiResponse() private val error = WooError(INVALID_RESPONSE, NETWORK_ERROR, "Invalid site ID") @@ -56,7 +56,7 @@ class WCTaxStoreTest { restClient, initCoroutineEngine(), mapper, - taxClassDao + taxRateDao ) // Insert the site into the db so it's available later when fetching tax classes @@ -108,7 +108,7 @@ class WCTaxStoreTest { val result = store.fetchTaxRateList(site, 1, 100) assertThat(this).isNotNull assertThat(result.isError).isFalse - assertThat(result.model).isEqualTo(taxRateApiResponse?.toList()) + assertThat(result).isEqualTo(WooResult(false)) } } diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt index 703cad167f..a7241134ac 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt @@ -14,7 +14,6 @@ import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooErrorType.GENERIC_ER import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooResult import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.TaxRateDto import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient -import org.wordpress.android.fluxc.persistence.TransactionExecutor import org.wordpress.android.fluxc.persistence.WCTaxSqlUtils import org.wordpress.android.fluxc.persistence.dao.TaxRateDao import org.wordpress.android.fluxc.tools.CoroutineEngine @@ -28,7 +27,6 @@ class WCTaxStore @Inject constructor( private val coroutineEngine: CoroutineEngine, private val mapper: WCTaxClassMapper, private val taxRateDao: TaxRateDao, - private val database: TransactionExecutor ) { companion object { // Just get everything @@ -77,7 +75,6 @@ class WCTaxStore @Inject constructor( when { response.isError -> WooResult(response.error) response.result != null -> { - database.executeInTransaction { if (page == 1) { taxRateDao.deleteAll(site.localId()) response.result.forEach { insertTaxRateToDatabase(it, site) } @@ -85,7 +82,6 @@ class WCTaxStore @Inject constructor( val canLoadMore = response.result.size == pageSize WooResult(canLoadMore) } - } else -> WooResult(WooError(GENERIC_ERROR, UNKNOWN)) } From a5e3efa214f594b3f0483153b1b7cedecc37580a Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Thu, 14 Sep 2023 08:11:57 -0400 Subject: [PATCH 40/55] Fix fetchTaxRates --- .../org/wordpress/android/fluxc/store/WCTaxStore.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt index a7241134ac..fdc2697bda 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt @@ -17,7 +17,7 @@ import org.wordpress.android.fluxc.network.rest.wpcom.wc.taxes.WCTaxRestClient import org.wordpress.android.fluxc.persistence.WCTaxSqlUtils import org.wordpress.android.fluxc.persistence.dao.TaxRateDao import org.wordpress.android.fluxc.tools.CoroutineEngine -import org.wordpress.android.util.AppLog +import org.wordpress.android.util.AppLog.T.API import javax.inject.Inject import javax.inject.Singleton @@ -41,7 +41,7 @@ class WCTaxStore @Inject constructor( WCTaxSqlUtils.getTaxClassesForSite(site.id) suspend fun fetchTaxClassList(site: SiteModel): WooResult> { - return coroutineEngine.withDefaultContext(AppLog.T.API, this, "fetchTaxClassList") { + return coroutineEngine.withDefaultContext(API, this, "fetchTaxClassList") { val response = restClient.fetchTaxClassList(site) return@withDefaultContext when { response.isError -> { @@ -70,15 +70,16 @@ class WCTaxStore @Inject constructor( page: Int = DEFAULT_PAGE, pageSize: Int = DEFAULT_PAGE_SIZE ): WooResult { - return coroutineEngine.withDefaultContext(AppLog.T.API, this, "fetchTaxRateList") { + return coroutineEngine.withDefaultContext(API, this, "fetchTaxRateList") { val response = restClient.fetchTaxRateList(site, page, pageSize) when { response.isError -> WooResult(response.error) response.result != null -> { if (page == 1) { taxRateDao.deleteAll(site.localId()) - response.result.forEach { insertTaxRateToDatabase(it, site) } } + response.result.forEach { insertTaxRateToDatabase(it, site) } + val canLoadMore = response.result.size == pageSize WooResult(canLoadMore) } From 3cdacc3e21a7fe478de5ec10716630b43e3f9c13 Mon Sep 17 00:00:00 2001 From: Rossana <30724184+rossanafmenezes@users.noreply.github.com> Date: Thu, 14 Sep 2023 10:45:42 -0400 Subject: [PATCH 41/55] Formatting changes: spacing, comments and indentation --- .../fluxc/model/taxes/TaxRateEntity.kt | 2 +- .../network/rest/wpcom/wc/taxes/TaxRateDto.kt | 22 +++++++++---------- .../android/fluxc/store/WCTaxStore.kt | 17 +++++++------- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt index caa0db28c9..54dc8ae5ce 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt @@ -7,7 +7,7 @@ import org.wordpress.android.fluxc.model.LocalOrRemoteId.RemoteId @Entity( tableName = "TaxRate", primaryKeys = ["id", "localSiteId"], - ) +) data class TaxRateEntity ( val id: RemoteId, val localSiteId: LocalId, diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/TaxRateDto.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/TaxRateDto.kt index bb7e1c725a..6b75b7fb94 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/TaxRateDto.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/taxes/TaxRateDto.kt @@ -6,19 +6,19 @@ import org.wordpress.android.fluxc.model.LocalOrRemoteId.RemoteId import org.wordpress.android.fluxc.model.taxes.TaxRateEntity data class TaxRateDto ( - @SerializedName("id") val id: Long, - @SerializedName("country") val country: String?, - @SerializedName("state" )val state: String?, + val id: Long, + val country: String?, + val state: String?, @SerializedName("postcode") val postCode: String?, - @SerializedName("city") val city: String?, + val city: String?, @SerializedName("postcodes") val postCodes: List?, - @SerializedName("cities") val cities: List?, - @SerializedName("rate") val rate: String?, - @SerializedName("name") val name: String?, - @SerializedName("priority") val priority: Int?, - @SerializedName("compound") val compound: Boolean?, - @SerializedName("shipping") val shipping: Boolean?, - @SerializedName("order") val order: Int?, + val cities: List?, + val rate: String?, + val name: String?, + val priority: Int?, + val compound: Boolean?, + val shipping: Boolean?, + val order: Int?, @SerializedName("class") val taxClass: String?, ) { fun toDataModel(localSiteId: LocalId): TaxRateEntity = diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt index fdc2697bda..e83270c146 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCTaxStore.kt @@ -29,7 +29,6 @@ class WCTaxStore @Inject constructor( private val taxRateDao: TaxRateDao, ) { companion object { - // Just get everything const val DEFAULT_PAGE_SIZE = 100 const val DEFAULT_PAGE = 1 } @@ -64,7 +63,9 @@ class WCTaxStore @Inject constructor( } } - // Returns a boolean indicating whether more Tax Rates can be fetched + /** + * returns a boolean indicating whether more Tax Rates can be fetched. + */ suspend fun fetchTaxRateList( site: SiteModel, page: Int = DEFAULT_PAGE, @@ -75,14 +76,14 @@ class WCTaxStore @Inject constructor( when { response.isError -> WooResult(response.error) response.result != null -> { - if (page == 1) { - taxRateDao.deleteAll(site.localId()) - } + if (page == 1) { + taxRateDao.deleteAll(site.localId()) + } response.result.forEach { insertTaxRateToDatabase(it, site) } - val canLoadMore = response.result.size == pageSize - WooResult(canLoadMore) - } + val canLoadMore = response.result.size == pageSize + WooResult(canLoadMore) + } else -> WooResult(WooError(GENERIC_ERROR, UNKNOWN)) } From a31696c3f0e1431b31e4522d9663d0db0b01cabb Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 14 Sep 2023 11:36:05 -0400 Subject: [PATCH 42/55] Replace page parameter default literals with constants --- .../android/fluxc/store/WCGlobalAttributeStore.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCGlobalAttributeStore.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCGlobalAttributeStore.kt index 2a91e4223d..d6390b6526 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCGlobalAttributeStore.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCGlobalAttributeStore.kt @@ -55,8 +55,8 @@ class WCGlobalAttributeStore @Inject constructor( suspend fun fetchAttributeTerms( site: SiteModel, attributeID: Long, - page: Int = 1, - pageSize: Int = 100 + page: Int = DEFAULT_PAGE_INDEX, + pageSize: Int = DEFAULT_PAGE_SIZE ) = restClient.fetchAllAttributeTerms(site, attributeID, page, pageSize) .result?.map { mapper.responseToAttributeTermModel(it, attributeID.toInt(), site) } ?.apply { @@ -194,4 +194,9 @@ class WCGlobalAttributeStore @Inject constructor( .model ?.let { updateSingleAttributeTermsMapping(attributeID.toInt(), termsId, site.id) } } + + companion object { + const val DEFAULT_PAGE_SIZE = 100 + const val DEFAULT_PAGE_INDEX = 1 + } } From 55bf716fa3400b10916fb0a6567b821e4b93edd9 Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Fri, 15 Sep 2023 09:49:19 +0200 Subject: [PATCH 43/55] Enable retrieving product reviews by and arrays of ids from DB --- .../fluxc/persistence/ProductSqlUtils.kt | 9 +++++ .../android/fluxc/store/WCProductStore.kt | 38 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/ProductSqlUtils.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/ProductSqlUtils.kt index 36adf414e4..9bd0990c0c 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/ProductSqlUtils.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/ProductSqlUtils.kt @@ -491,6 +491,15 @@ object ProductSqlUtils { .asModel } + fun getProductReviewsByReviewIds(reviewIds: List): List { + return WellSql.select(WCProductReviewModel::class.java) + .where() + .isIn(WCProductReviewModelTable.REMOTE_PRODUCT_REVIEW_ID, reviewIds) + .endWhere() + .orderBy(WCProductReviewModelTable.DATE_CREATED, SelectQuery.ORDER_DESCENDING) + .asModel + } + fun getProductReviewsForProductAndSiteId( localSiteId: Int, remoteProductId: Long diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCProductStore.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCProductStore.kt index cde9d6d395..c8c8278f6c 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCProductStore.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCProductStore.kt @@ -84,6 +84,7 @@ class WCProductStore @Inject constructor( override fun toString() = name.toLowerCase(Locale.US) } + enum class SkuSearchOptions { Disabled, ExactSearch, PartialMatch } @@ -825,6 +826,9 @@ class WCProductStore @Inject constructor( fun getProductReviewsForSite(site: SiteModel): List = ProductSqlUtils.getProductReviewsForSite(site) + fun getProductReviewsByReviewId(reviewIds: List): List = + ProductSqlUtils.getProductReviewsByReviewIds(reviewIds) + fun getProductReviewsForProductAndSiteId(localSiteId: Int, remoteProductId: Long): List = ProductSqlUtils.getProductReviewsForProductAndSiteId(localSiteId, remoteProductId) @@ -887,64 +891,92 @@ class WCProductStore @Inject constructor( // remote actions WCProductAction.FETCH_PRODUCT_SKU_AVAILABILITY -> fetchProductSkuAvailability(action.payload as FetchProductSkuAvailabilityPayload) + WCProductAction.FETCH_PRODUCTS -> fetchProducts(action.payload as FetchProductsPayload) + WCProductAction.SEARCH_PRODUCTS -> searchProducts(action.payload as SearchProductsPayload) + WCProductAction.UPDATE_PRODUCT_IMAGES -> updateProductImages(action.payload as UpdateProductImagesPayload) + WCProductAction.UPDATE_PRODUCT -> updateProduct(action.payload as UpdateProductPayload) + WCProductAction.FETCH_SINGLE_PRODUCT_SHIPPING_CLASS -> fetchProductShippingClass(action.payload as FetchSingleProductShippingClassPayload) + WCProductAction.FETCH_PRODUCT_SHIPPING_CLASS_LIST -> fetchProductShippingClasses(action.payload as FetchProductShippingClassListPayload) + WCProductAction.FETCH_PRODUCT_PASSWORD -> fetchProductPassword(action.payload as FetchProductPasswordPayload) + WCProductAction.UPDATE_PRODUCT_PASSWORD -> updateProductPassword(action.payload as UpdateProductPasswordPayload) + WCProductAction.FETCH_PRODUCT_CATEGORIES -> fetchProductCategories(action.payload as FetchProductCategoriesPayload) + WCProductAction.ADD_PRODUCT_CATEGORY -> addProductCategory(action.payload as AddProductCategoryPayload) + WCProductAction.FETCH_PRODUCT_TAGS -> fetchProductTags(action.payload as FetchProductTagsPayload) + WCProductAction.ADD_PRODUCT_TAGS -> addProductTags(action.payload as AddProductTagsPayload) + WCProductAction.ADD_PRODUCT -> addProduct(action.payload as AddProductPayload) + WCProductAction.DELETE_PRODUCT -> deleteProduct(action.payload as DeleteProductPayload) // remote responses WCProductAction.FETCHED_PRODUCT_SKU_AVAILABILITY -> handleFetchProductSkuAvailabilityCompleted(action.payload as RemoteProductSkuAvailabilityPayload) + WCProductAction.FETCHED_PRODUCTS -> handleFetchProductsCompleted(action.payload as RemoteProductListPayload) + WCProductAction.SEARCHED_PRODUCTS -> handleSearchProductsCompleted(action.payload as RemoteSearchProductsPayload) + WCProductAction.UPDATED_PRODUCT_IMAGES -> handleUpdateProductImages(action.payload as RemoteUpdateProductImagesPayload) + WCProductAction.UPDATED_PRODUCT -> handleUpdateProduct(action.payload as RemoteUpdateProductPayload) + WCProductAction.FETCHED_PRODUCT_SHIPPING_CLASS_LIST -> handleFetchProductShippingClassesCompleted(action.payload as RemoteProductShippingClassListPayload) + WCProductAction.FETCHED_SINGLE_PRODUCT_SHIPPING_CLASS -> handleFetchProductShippingClassCompleted(action.payload as RemoteProductShippingClassPayload) + WCProductAction.FETCHED_PRODUCT_PASSWORD -> handleFetchProductPasswordCompleted(action.payload as RemoteProductPasswordPayload) + WCProductAction.UPDATED_PRODUCT_PASSWORD -> handleUpdatedProductPasswordCompleted(action.payload as RemoteUpdatedProductPasswordPayload) + WCProductAction.FETCHED_PRODUCT_CATEGORIES -> handleFetchProductCategories(action.payload as RemoteProductCategoriesPayload) + WCProductAction.ADDED_PRODUCT_CATEGORY -> handleAddProductCategory(action.payload as RemoteAddProductCategoryResponsePayload) + WCProductAction.FETCHED_PRODUCT_TAGS -> handleFetchProductTagsCompleted(action.payload as RemoteProductTagsPayload) + WCProductAction.ADDED_PRODUCT_TAGS -> handleAddProductTags(action.payload as RemoteAddProductTagsResponsePayload) + WCProductAction.ADDED_PRODUCT -> handleAddNewProduct(action.payload as RemoteAddProductPayload) + WCProductAction.DELETED_PRODUCT -> handleDeleteProduct(action.payload as RemoteDeleteProductPayload) } @@ -1447,6 +1479,7 @@ class WCProductStore @Inject constructor( val canLoadMore = response.result.size == pageSize WooResult(canLoadMore) } + else -> WooResult(WooError(WooErrorType.GENERIC_ERROR, UNKNOWN)) } } @@ -1492,6 +1525,7 @@ class WCProductStore @Inject constructor( val canLoadMore = response.result.size == pageSize WooResult(canLoadMore) } + else -> WooResult(WooError(WooErrorType.GENERIC_ERROR, UNKNOWN)) } } @@ -1525,6 +1559,7 @@ class WCProductStore @Inject constructor( val canLoadMore = response.result.size == pageSize WooResult(ProductSearchResult(products, canLoadMore)) } + else -> WooResult(WooError(WooErrorType.GENERIC_ERROR, UNKNOWN)) } } @@ -1560,6 +1595,7 @@ class WCProductStore @Inject constructor( val canLoadMore = response.result.size == pageSize WooResult(ProductCategorySearchResult(categories, canLoadMore)) } + else -> WooResult(WooError(WooErrorType.GENERIC_ERROR, UNKNOWN)) } } @@ -1599,6 +1635,7 @@ class WCProductStore @Inject constructor( val canLoadMore = response.result.size == pageSize WooResult(canLoadMore) } + else -> WooResult(WooError(WooErrorType.GENERIC_ERROR, UNKNOWN)) } } @@ -1649,6 +1686,7 @@ class WCProductStore @Inject constructor( response.result != null -> { WooResult(response.result.sumOf { it.total }) } + else -> WooResult(WooError(WooErrorType.GENERIC_ERROR, UNKNOWN)) } } From d8249165c4ff8add8f9f7ad95f84e0851c072c39 Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Fri, 15 Sep 2023 15:13:53 +0200 Subject: [PATCH 44/55] Fix pagination issues for unread reviews --- .../kotlin/org/wordpress/android/fluxc/store/WCProductStore.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCProductStore.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCProductStore.kt index c8c8278f6c..f0f24c0186 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCProductStore.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCProductStore.kt @@ -1233,7 +1233,7 @@ class WCProductStore @Inject constructor( // Clear existing product reviews if this is a fresh fetch (loadMore = false). // This is the simplest way to keep our local reviews in sync with remote reviews // in case of deletions. - if (!response.loadedMore) { + if (!response.loadedMore && payload.reviewIds == null) { ProductSqlUtils.deleteAllProductReviewsForSite(response.site) } val rowsAffected = ProductSqlUtils.insertOrUpdateProductReviews(response.reviews) From 768f00f71ab2298f02224aefa5f250a08516f17a Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Fri, 15 Sep 2023 16:29:56 +0200 Subject: [PATCH 45/55] Make explicit when we are deleting the existing cached reviews --- .../org/wordpress/android/fluxc/store/WCProductStore.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCProductStore.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCProductStore.kt index f0f24c0186..18aec06f7a 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCProductStore.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCProductStore.kt @@ -1221,7 +1221,10 @@ class WCProductStore @Inject constructor( with(payload) { wcProductRestClient.fetchProductShippingClassList(site, pageSize, offset) } } - suspend fun fetchProductReviews(payload: FetchProductReviewsPayload): OnProductReviewChanged { + suspend fun fetchProductReviews( + payload: FetchProductReviewsPayload, + deletePreviouslyCachedReviews: Boolean = true + ): OnProductReviewChanged { return coroutineEngine.withDefaultContext(API, this, "fetchProductReviews") { val response = with(payload) { wcProductRestClient.fetchProductReviews(site, offset, reviewIds, productIds, filterByStatus) @@ -1232,8 +1235,8 @@ class WCProductStore @Inject constructor( } else { // Clear existing product reviews if this is a fresh fetch (loadMore = false). // This is the simplest way to keep our local reviews in sync with remote reviews - // in case of deletions. - if (!response.loadedMore && payload.reviewIds == null) { + // in case of deletions or status updates. + if (deletePreviouslyCachedReviews) { ProductSqlUtils.deleteAllProductReviewsForSite(response.site) } val rowsAffected = ProductSqlUtils.insertOrUpdateProductReviews(response.reviews) From 3ea2573524e443d23269f8e27e7340c67d641034 Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Fri, 15 Sep 2023 16:43:19 +0200 Subject: [PATCH 46/55] Remove unneeded field from --- .../fluxc/network/rest/wpcom/wc/product/ProductRestClient.kt | 3 +-- .../kotlin/org/wordpress/android/fluxc/store/WCProductStore.kt | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/product/ProductRestClient.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/product/ProductRestClient.kt index fa4cce4d93..c6bafb484c 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/product/ProductRestClient.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/product/ProductRestClient.kt @@ -1488,8 +1488,7 @@ class ProductRestClient @Inject constructor( reviews, productIds, filterByStatus, - offset > 0, - reviews.size == WCProductStore.NUM_REVIEWS_PER_FETCH + canLoadMore = reviews.size == WCProductStore.NUM_REVIEWS_PER_FETCH ) } else { FetchProductReviewsResponsePayload( diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCProductStore.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCProductStore.kt index 18aec06f7a..96adf10595 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCProductStore.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCProductStore.kt @@ -568,7 +568,6 @@ class WCProductStore @Inject constructor( val reviews: List = emptyList(), val filterProductIds: List? = null, val filterByStatus: List? = null, - val loadedMore: Boolean = false, val canLoadMore: Boolean = false ) : Payload() { constructor(error: ProductError, site: SiteModel) : this(site) { From 09a5be01f69ee068b8a0a27fecedcb91038bb9f5 Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Fri, 15 Sep 2023 17:21:08 +0200 Subject: [PATCH 47/55] Fix test compile issues --- .../wordpress/android/fluxc/mocked/MockedStack_WCProductsTest.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/example/src/androidTest/java/org/wordpress/android/fluxc/mocked/MockedStack_WCProductsTest.kt b/example/src/androidTest/java/org/wordpress/android/fluxc/mocked/MockedStack_WCProductsTest.kt index d26ee94e91..a75f92cb6c 100644 --- a/example/src/androidTest/java/org/wordpress/android/fluxc/mocked/MockedStack_WCProductsTest.kt +++ b/example/src/androidTest/java/org/wordpress/android/fluxc/mocked/MockedStack_WCProductsTest.kt @@ -505,7 +505,6 @@ class MockedStack_WCProductsTest : MockedStack_Base() { assertEquals(25, payload.reviews.size) assertNull(payload.filterProductIds) assertNull(payload.filterByStatus) - assertFalse(payload.loadedMore) assertTrue(payload.canLoadMore) // Save product reviews to the database From 5f96f8fbfde6c3be32b4d2e3d92bbab6cf0f8f34 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Sun, 17 Sep 2023 00:28:55 +0100 Subject: [PATCH 48/55] Make sure the plan features are fetched correctly when fetching sites --- .../rest/wpcom/site/SiteRestClientTest.kt | 46 +++++++++++++++++-- .../src/main/resources/wp-com-endpoints.txt | 1 + .../network/rest/wpcom/site/SiteRestClient.kt | 38 ++++++++++++++- .../wpcom/site/SitesFeaturesRestResponse.kt | 9 ++++ 4 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/site/SitesFeaturesRestResponse.kt diff --git a/example/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/site/SiteRestClientTest.kt b/example/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/site/SiteRestClientTest.kt index 9cfe7f6278..80822f5eb0 100644 --- a/example/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/site/SiteRestClientTest.kt +++ b/example/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/site/SiteRestClientTest.kt @@ -112,7 +112,7 @@ class SiteRestClientTest { } @Test - fun `returns fetched sites`() = test { + fun `returns fetched sites using filter`() = test { val response = SiteWPComRestResponse() response.ID = siteId val name = "Updated name" @@ -123,15 +123,18 @@ class SiteRestClientTest { sitesResponse.sites = listOf(response) initSitesResponse(data = sitesResponse) + initSitesFeaturesResponse(data = SitesFeaturesRestResponse(emptyMap())) val responseModel = restClient.fetchSites(listOf(WPCOM), false) assertThat(responseModel.sites).hasSize(1) assertThat(responseModel.sites[0].name).isEqualTo(name) assertThat(responseModel.sites[0].siteId).isEqualTo(siteId) - assertThat(urlCaptor.lastValue) + assertThat(urlCaptor.firstValue) .isEqualTo("https://public-api.wordpress.com/rest/v1.2/me/sites/") - assertThat(paramsCaptor.lastValue).isEqualTo( + assertThat(urlCaptor.lastValue) + .isEqualTo("https://public-api.wordpress.com/rest/v1.1/me/sites/features/") + assertThat(paramsCaptor.firstValue).isEqualTo( mapOf( "filters" to "wpcom", "fields" to "ID,URL,name,description,jetpack,jetpack_connection," + @@ -141,6 +144,35 @@ class SiteRestClientTest { ) } + @Test + fun `returns fetched sites when not filtering`() = test { + val response = SiteWPComRestResponse() + response.ID = siteId + val name = "Updated name" + response.name = name + response.URL = "site.com" + + val sitesResponse = SitesResponse() + sitesResponse.sites = listOf(response) + + initSitesResponse(data = sitesResponse) + + val responseModel = restClient.fetchSites(emptyList(), false) + assertThat(responseModel.sites).hasSize(1) + assertThat(responseModel.sites[0].name).isEqualTo(name) + assertThat(responseModel.sites[0].siteId).isEqualTo(siteId) + + assertThat(urlCaptor.firstValue) + .isEqualTo("https://public-api.wordpress.com/rest/v1.1/me/sites/") + assertThat(paramsCaptor.firstValue).isEqualTo( + mapOf( + "fields" to "ID,URL,name,description,jetpack,jetpack_connection," + + "visible,is_private,options,plan,capabilities,quota,icon,meta,zendesk_site_meta," + + "organization_id,was_ecommerce_trial" + ) + ) + } + @Test fun `fetched sites can filter JP connected package sites`() = test { val response = SiteWPComRestResponse() @@ -155,6 +187,7 @@ class SiteRestClientTest { sitesResponse.sites = listOf(response) initSitesResponse(data = sitesResponse) + initSitesFeaturesResponse(data = SitesFeaturesRestResponse(features = emptyMap())) val responseModel = restClient.fetchSites(listOf(WPCOM), true) @@ -521,6 +554,13 @@ class SiteRestClientTest { return initGetResponse(PostFormatsResponse::class.java, data ?: mock(), error) } + private suspend fun initSitesFeaturesResponse( + data: SitesFeaturesRestResponse? = null, + error: WPComGsonNetworkError? = null + ): Response { + return initGetResponse(SitesFeaturesRestResponse::class.java, data ?: mock(), error) + } + private suspend fun initGetResponse( clazz: Class, data: T, diff --git a/fluxc-processor/src/main/resources/wp-com-endpoints.txt b/fluxc-processor/src/main/resources/wp-com-endpoints.txt index 1164690309..408903117f 100644 --- a/fluxc-processor/src/main/resources/wp-com-endpoints.txt +++ b/fluxc-processor/src/main/resources/wp-com-endpoints.txt @@ -19,6 +19,7 @@ /me/domain-contact-information/ /me/settings/ /me/sites/ +/me/sites/features /me/send-verification-email/ /me/social-login/connect/ /me/username/ diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/site/SiteRestClient.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/site/SiteRestClient.kt index eb0470c063..9d14626d9b 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/site/SiteRestClient.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/site/SiteRestClient.kt @@ -132,16 +132,36 @@ class SiteRestClient @Inject constructor( val site: SiteModel? = null ) : Payload() + @Suppress("ComplexMethod") suspend fun fetchSites(filters: List, filterJetpackConnectedPackageSite: Boolean): SitesModel { + val useV2Endpoint = filters.isNotEmpty() val params = getFetchSitesParams(filters) - val url = WPCOMREST.me.sites.urlV1_2 + val url = WPCOMREST.me.sites.let { if (useV2Endpoint) it.urlV1_2 else it.urlV1_1 } val response = wpComGsonRequestBuilder.syncGetRequest(this, url, params, SitesResponse::class.java) + + val siteFeatures = if (useV2Endpoint) { + // The v1.2 version doesn't include the plan features, so use the specific endpoint to fetch them separately + fetchSitesFeatures().let { + if (it is Error) { + val result = SitesModel() + result.error = it.error + return result + } + (it as Success).data + } + } else null + return when (response) { is Success -> { val siteArray = mutableListOf() val jetpackCPSiteArray = mutableListOf() for (siteResponse in response.data.sites) { val siteModel = siteResponseToSiteModel(siteResponse) + + siteFeatures?.get(siteModel.siteId)?.let { + siteModel.planActiveFeatures = it.joinToString(",") + } + if (siteModel.isJetpackCPConnected) jetpackCPSiteArray.add(siteModel) // see https://github.com/wordpress-mobile/WordPress-Android/issues/15540#issuecomment-993752880 if (filterJetpackConnectedPackageSite && siteModel.isJetpackCPConnected) continue @@ -149,6 +169,7 @@ class SiteRestClient @Inject constructor( } SitesModel(siteArray, jetpackCPSiteArray) } + is Error -> { val payload = SitesModel(emptyList()) payload.error = response.error @@ -157,6 +178,21 @@ class SiteRestClient @Inject constructor( } } + private suspend fun fetchSitesFeatures(): Response>> { + val url = WPCOMREST.me.sites.features.urlV1_1 + return wpComGsonRequestBuilder.syncGetRequest( + restClient = this, + url = url, + params = emptyMap(), + clazz = SitesFeaturesRestResponse::class.java + ).let { + when (it) { + is Success -> Success(it.data.features.mapValues { it.value.active }) + is Error -> Error(it.error) + } + } + } + private fun getFetchSitesParams(filters: List): Map { val params = mutableMapOf() if (filters.isNotEmpty()) params[FILTERS] = TextUtils.join(",", filters) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/site/SitesFeaturesRestResponse.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/site/SitesFeaturesRestResponse.kt new file mode 100644 index 0000000000..08141ef536 --- /dev/null +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/site/SitesFeaturesRestResponse.kt @@ -0,0 +1,9 @@ +package org.wordpress.android.fluxc.network.rest.wpcom.site + +data class SitesFeaturesRestResponse( + val features: Map +) + +data class SiteFeatures( + val active: List +) From bb10a962435d7018dfc157a0ba8411c28571a812 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Sun, 17 Sep 2023 01:34:13 +0100 Subject: [PATCH 49/55] Add ability to identify WooExpress sample products --- .../android/fluxc/model/StripProductMetaData.kt | 4 +++- .../org/wordpress/android/fluxc/model/WCProductModel.kt | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/StripProductMetaData.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/StripProductMetaData.kt index 64fd1c64f6..9c1371712b 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/StripProductMetaData.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/StripProductMetaData.kt @@ -3,9 +3,10 @@ package org.wordpress.android.fluxc.model import com.google.gson.Gson import com.google.gson.JsonArray import com.google.gson.JsonObject -import org.wordpress.android.fluxc.model.WCProductModel.SubscriptionMetadataKeys import org.wordpress.android.fluxc.model.WCProductModel.AddOnsMetadataKeys +import org.wordpress.android.fluxc.model.WCProductModel.OtherKeys import org.wordpress.android.fluxc.model.WCProductModel.QuantityRulesMetadataKeys +import org.wordpress.android.fluxc.model.WCProductModel.SubscriptionMetadataKeys import org.wordpress.android.fluxc.utils.EMPTY_JSON_ARRAY import org.wordpress.android.fluxc.utils.isElementNullOrEmpty import javax.inject.Inject @@ -30,6 +31,7 @@ class StripProductMetaData @Inject internal constructor(private val gson: Gson) add(AddOnsMetadataKeys.ADDONS_METADATA_KEY) addAll(QuantityRulesMetadataKeys.ALL_KEYS) addAll(SubscriptionMetadataKeys.ALL_KEYS) + add(OtherKeys.HEAD_START_POST) } } } diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/WCProductModel.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/WCProductModel.kt index 3f696fa1d5..9c84c4c628 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/WCProductModel.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/WCProductModel.kt @@ -119,6 +119,11 @@ data class WCProductModel(@PrimaryKey @Column private var id: Int = 0) : Identif ?.find { it.key == ADDONS_METADATA_KEY } ?.addons + val isSampleProduct: Boolean + get() = Gson().fromJson(metadata, Array::class.java) + ?.any { it.key == OtherKeys.HEAD_START_POST && it.value == "_hs_extra" } + ?: false + @Suppress("SwallowedException", "TooGenericExceptionCaught") private val WCMetaData.addons get() = try { @@ -596,4 +601,8 @@ data class WCProductModel(@PrimaryKey @Column private var id: Int = 0) : Identif ALLOW_COMBINATION ) } + + object OtherKeys { + const val HEAD_START_POST = "_headstart_post" + } } From c81c1bf984c39df536941616fb85b4af04706dd4 Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Tue, 19 Sep 2023 10:43:00 +0200 Subject: [PATCH 50/55] Remove default value for deletePreviouslyCachedReviews param --- .../release/ReleaseStack_WCProductTest.kt | 194 ++++++++++++------ .../ui/products/WooProductsFragment.kt | 8 +- .../android/fluxc/store/WCProductStore.kt | 2 +- 3 files changed, 142 insertions(+), 62 deletions(-) diff --git a/example/src/androidTest/java/org/wordpress/android/fluxc/release/ReleaseStack_WCProductTest.kt b/example/src/androidTest/java/org/wordpress/android/fluxc/release/ReleaseStack_WCProductTest.kt index b03886b650..c78de558e4 100644 --- a/example/src/androidTest/java/org/wordpress/android/fluxc/release/ReleaseStack_WCProductTest.kt +++ b/example/src/androidTest/java/org/wordpress/android/fluxc/release/ReleaseStack_WCProductTest.kt @@ -81,7 +81,9 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { } @Inject internal lateinit var productStore: WCProductStore - @Inject internal lateinit var mediaStore: MediaStore // must be injected for onMediaListFetched() + + @Inject + internal lateinit var mediaStore: MediaStore // must be injected for onMediaListFetched() private var nextEvent: TestEvent = TestEvent.NONE private val productModel = WCProductModel(8).apply { @@ -131,7 +133,12 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { ProductSqlUtils.deleteProductsForSite(sSite) assertEquals(ProductSqlUtils.getProductCountForSite(sSite), 0) - productStore.fetchSingleProduct(FetchSingleProductPayload(sSite, productModel.remoteProductId)) + productStore.fetchSingleProduct( + FetchSingleProductPayload( + sSite, + productModel.remoteProductId + ) + ) // Verify results val fetchedProduct = productStore.getProductByRemoteId(sSite, productModel.remoteProductId) @@ -147,10 +154,16 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { @Test fun testFetchSingleVariation() = runBlocking { // remove all variation for this site and verify there are none - ProductSqlUtils.deleteVariationsForProduct(sSite, productModelWithVariations.remoteProductId) + ProductSqlUtils.deleteVariationsForProduct( + sSite, + productModelWithVariations.remoteProductId + ) assertEquals( - ProductSqlUtils.getVariationsForProduct(sSite, productModelWithVariations.remoteProductId).size, - 0 + ProductSqlUtils.getVariationsForProduct( + sSite, + productModelWithVariations.remoteProductId + ).size, + 0 ) val result = productStore.fetchSingleVariation( @@ -164,16 +177,19 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { // Verify results val fetchedVariation = productStore.getVariationByRemoteId( - sSite, - variationModel.remoteProductId, - variationModel.remoteVariationId + sSite, + variationModel.remoteProductId, + variationModel.remoteVariationId ) assertNotNull(fetchedVariation) assertEquals(fetchedVariation!!.remoteProductId, variationModel.remoteProductId) assertEquals(fetchedVariation.remoteVariationId, variationModel.remoteVariationId) // Verify there's only one variation for this site - assertEquals(1, ProductSqlUtils.getVariationsForProduct(sSite, variationModel.remoteProductId).size) + assertEquals( + 1, + ProductSqlUtils.getVariationsForProduct(sSite, variationModel.remoteProductId).size + ) } @Throws(InterruptedException::class) @@ -186,8 +202,8 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { nextEvent = TestEvent.FETCHED_PRODUCTS mCountDownLatch = CountDownLatch(1) mDispatcher.dispatch( - WCProductActionBuilder - .newFetchProductsAction(FetchProductsPayload(sSite)) + WCProductActionBuilder + .newFetchProductsAction(FetchProductsPayload(sSite)) ) assertTrue(mCountDownLatch.await(TestUtils.DEFAULT_TIMEOUT_MS.toLong(), MILLISECONDS)) @@ -200,8 +216,16 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { @Test fun testFetchProductVariations() = runBlocking { // remove all variations for this product and verify there are none - ProductSqlUtils.deleteVariationsForProduct(sSite, productModelWithVariations.remoteProductId) - assertEquals(ProductSqlUtils.getVariationsForProduct(sSite, productModelWithVariations.remoteProductId).size, 0) + ProductSqlUtils.deleteVariationsForProduct( + sSite, + productModelWithVariations.remoteProductId + ) + assertEquals( + ProductSqlUtils.getVariationsForProduct( + sSite, + productModelWithVariations.remoteProductId + ).size, 0 + ) productStore.fetchProductVariations( FetchProductVariationsPayload( @@ -211,7 +235,10 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { ) // Verify results - val fetchedVariations = productStore.getVariationsForProduct(sSite, productModelWithVariations.remoteProductId) + val fetchedVariations = productStore.getVariationsForProduct( + sSite, + productModelWithVariations.remoteProductId + ) assertNotEquals(fetchedVariations.size, 0) } @@ -228,9 +255,9 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { nextEvent = TestEvent.FETCHED_PRODUCT_SHIPPING_CLASS_LIST mCountDownLatch = CountDownLatch(1) mDispatcher.dispatch( - WCProductActionBuilder.newFetchProductShippingClassListAction( - FetchProductShippingClassListPayload(sSite) - ) + WCProductActionBuilder.newFetchProductShippingClassListAction( + FetchProductShippingClassListPayload(sSite) + ) ) assertTrue(mCountDownLatch.await(TestUtils.DEFAULT_TIMEOUT_MS.toLong(), MILLISECONDS)) @@ -253,15 +280,15 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { nextEvent = TestEvent.FETCHED_SINGLE_PRODUCT_SHIPPING_CLASS mCountDownLatch = CountDownLatch(1) mDispatcher.dispatch( - WCProductActionBuilder.newFetchSingleProductShippingClassAction( - FetchSingleProductShippingClassPayload(sSite, remoteShippingClassId) - ) + WCProductActionBuilder.newFetchSingleProductShippingClassAction( + FetchSingleProductShippingClassPayload(sSite, remoteShippingClassId) + ) ) assertTrue(mCountDownLatch.await(TestUtils.DEFAULT_TIMEOUT_MS.toLong(), MILLISECONDS)) // Verify results val fetchedShippingClasses = productStore.getShippingClassByRemoteId( - sSite, remoteShippingClassId + sSite, remoteShippingClassId ) assertNotNull(fetchedShippingClasses) } @@ -276,7 +303,11 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { nextEvent = TestEvent.FETCH_PRODUCT_CATEGORIES mCountDownLatch = CountDownLatch(1) mDispatcher.dispatch( - WCProductActionBuilder.newFetchProductCategoriesAction(FetchProductCategoriesPayload(sSite)) + WCProductActionBuilder.newFetchProductCategoriesAction( + FetchProductCategoriesPayload( + sSite + ) + ) ) assertTrue(mCountDownLatch.await(TestUtils.DEFAULT_TIMEOUT_MS.toLong(), MILLISECONDS)) @@ -300,9 +331,9 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { name = "Test" + Random.nextInt(0, 10000) } mDispatcher.dispatch( - WCProductActionBuilder.newAddProductCategoryAction( - AddProductCategoryPayload(sSite, productCategoryModel) - ) + WCProductActionBuilder.newAddProductCategoryAction( + AddProductCategoryPayload(sSite, productCategoryModel) + ) ) assertTrue(mCountDownLatch.await(TestUtils.DEFAULT_TIMEOUT_MS.toLong(), MILLISECONDS)) @@ -322,7 +353,10 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { productStore.deleteAllProductReviews() assertEquals(0, ProductSqlUtils.getProductReviewsForSite(sSite).size) - productStore.fetchProductReviews(FetchProductReviewsPayload(sSite, offset = 0)) + productStore.fetchProductReviews( + FetchProductReviewsPayload(sSite, offset = 0), + deletePreviouslyCachedReviews = false + ) // Verify results val fetchedReviewsAll = productStore.getProductReviewsForSite(sSite) @@ -338,7 +372,10 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { productStore.deleteAllProductReviews() assertEquals(0, ProductSqlUtils.getProductReviewsForSite(sSite).size) - productStore.fetchProductReviews(FetchProductReviewsPayload(sSite, reviewIds = idsToFetch, offset = 0)) + productStore.fetchProductReviews( + FetchProductReviewsPayload(sSite, reviewIds = idsToFetch, offset = 0), + deletePreviouslyCachedReviews = false + ) // Verify results val fetchReviewsId = productStore.getProductReviewsForSite(sSite) @@ -352,13 +389,25 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { // Check to see how many reviews currently exist for these product IDs before deleting // from the database - val reviewsByProduct = productIdsToFetch.map { productStore.getProductReviewsForProductAndSiteId(sSite.id, it) } + val reviewsByProduct = productIdsToFetch.map { + productStore.getProductReviewsForProductAndSiteId( + sSite.id, + it + ) + } // Remove all product reviews from the database productStore.deleteAllProductReviews() assertEquals(0, ProductSqlUtils.getProductReviewsForSite(sSite).size) - productStore.fetchProductReviews(FetchProductReviewsPayload(sSite, productIds = productIdsToFetch, offset = 0)) + productStore.fetchProductReviews( + FetchProductReviewsPayload( + sSite, + productIds = productIdsToFetch, + offset = 0 + ), + deletePreviouslyCachedReviews = false + ) // Verify results val fetchedReviewsForProduct = productStore.getProductReviewsForSite(sSite) @@ -372,14 +421,14 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { nextEvent = TestEvent.UPDATED_PRODUCT_PASSWORD mCountDownLatch = CountDownLatch(1) mDispatcher.dispatch( - WCProductActionBuilder - .newUpdateProductPasswordAction( - UpdateProductPasswordPayload( - sSite, - productModel.remoteProductId, - updatedPassword - ) - ) + WCProductActionBuilder + .newUpdateProductPasswordAction( + UpdateProductPasswordPayload( + sSite, + productModel.remoteProductId, + updatedPassword + ) + ) ) assertTrue(mCountDownLatch.await(TestUtils.DEFAULT_TIMEOUT_MS.toLong(), MILLISECONDS)) @@ -387,8 +436,13 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { nextEvent = TestEvent.FETCHED_PRODUCT_PASSWORD mCountDownLatch = CountDownLatch(1) mDispatcher.dispatch( - WCProductActionBuilder - .newFetchProductPasswordAction(FetchProductPasswordPayload(sSite, productModel.remoteProductId)) + WCProductActionBuilder + .newFetchProductPasswordAction( + FetchProductPasswordPayload( + sSite, + productModel.remoteProductId + ) + ) ) assertTrue(mCountDownLatch.await(TestUtils.DEFAULT_TIMEOUT_MS.toLong(), MILLISECONDS)) } @@ -400,7 +454,12 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { productStore.deleteAllProductReviews() assertEquals(0, ProductSqlUtils.getProductReviewsForSite(sSite).size) - productStore.fetchSingleProductReview(FetchSingleProductReviewPayload(sSite, remoteProductReviewId)) + productStore.fetchSingleProductReview( + FetchSingleProductReviewPayload( + sSite, + remoteProductReviewId + ) + ) // Verify results val review = productStore.getProductReviewByRemoteId(sSite.id, remoteProductReviewId) @@ -413,7 +472,7 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { // Verify results - review should be deleted from db val savedReview = productStore - .getProductReviewByRemoteId(sSite.id, remoteProductReviewId) + .getProductReviewByRemoteId(sSite.id, remoteProductReviewId) assertNull(savedReview) } @@ -425,7 +484,7 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { // Verify results val savedReview = productStore - .getProductReviewByRemoteId(sSite.id, remoteProductReviewId) + .getProductReviewByRemoteId(sSite.id, remoteProductReviewId) assertNotNull(savedReview) assertEquals(newStatus, savedReview!!.status) } @@ -437,7 +496,7 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { // Verify results - review should be deleted from db val savedReview = productStore - .getProductReviewByRemoteId(sSite.id, remoteProductReviewId) + .getProductReviewByRemoteId(sSite.id, remoteProductReviewId) assertNull(savedReview) } @@ -448,7 +507,7 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { // Verify results val savedReview = productStore - .getProductReviewByRemoteId(sSite.id, remoteProductReviewId) + .getProductReviewByRemoteId(sSite.id, remoteProductReviewId) assertNotNull(savedReview) assertEquals(newStatus, savedReview!!.status) } @@ -474,9 +533,9 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { it.add(WCProductImageModel.fromMediaModel(mediaModelForProduct)) } mDispatcher.dispatch( - WCProductActionBuilder.newUpdateProductImagesAction( - UpdateProductImagesPayload(sSite, productModel.remoteProductId, imageList) - ) + WCProductActionBuilder.newUpdateProductImagesAction( + UpdateProductImagesPayload(sSite, productModel.remoteProductId, imageList) + ) ) assertTrue(mCountDownLatch.await(TestUtils.DEFAULT_TIMEOUT_MS.toLong(), MILLISECONDS)) @@ -539,7 +598,7 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { nextEvent = TestEvent.UPDATED_PRODUCT mCountDownLatch = CountDownLatch(1) mDispatcher.dispatch( - WCProductActionBuilder.newUpdateProductAction(UpdateProductPayload(sSite, productModel)) + WCProductActionBuilder.newUpdateProductAction(UpdateProductPayload(sSite, productModel)) ) assertTrue(mCountDownLatch.await(TestUtils.DEFAULT_TIMEOUT_MS.toLong(), MILLISECONDS)) @@ -591,7 +650,7 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { nextEvent = TestEvent.UPDATED_PRODUCT mCountDownLatch = CountDownLatch(1) mDispatcher.dispatch( - WCProductActionBuilder.newUpdateProductAction(UpdateProductPayload(sSite, productModel)) + WCProductActionBuilder.newUpdateProductAction(UpdateProductPayload(sSite, productModel)) ) assertTrue(mCountDownLatch.await(TestUtils.DEFAULT_TIMEOUT_MS.toLong(), MILLISECONDS)) @@ -626,9 +685,9 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { } val updatedVariation = productStore.getVariationByRemoteId( - sSite, - variationModel.remoteProductId, - variationModel.remoteVariationId + sSite, + variationModel.remoteProductId, + variationModel.remoteVariationId ) assertNotNull(updatedVariation) assertEquals(variationModel.remoteProductId, updatedVariation?.remoteProductId) @@ -647,7 +706,11 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { nextEvent = TestEvent.FETCHED_PRODUCT_TAGS mCountDownLatch = CountDownLatch(1) - mDispatcher.dispatch(WCProductActionBuilder.newFetchProductTagsAction(FetchProductTagsPayload(sSite))) + mDispatcher.dispatch( + WCProductActionBuilder.newFetchProductTagsAction( + FetchProductTagsPayload(sSite) + ) + ) assertTrue(mCountDownLatch.await(TestUtils.DEFAULT_TIMEOUT_MS.toLong(), MILLISECONDS)) // Verify results @@ -667,9 +730,9 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { val productTags = listOf("Test" + Date().time, "Test1" + Date().time) mDispatcher.dispatch( - WCProductActionBuilder.newAddProductTagsAction( - AddProductTagsPayload(sSite, productTags) - ) + WCProductActionBuilder.newAddProductTagsAction( + AddProductTagsPayload(sSite, productTags) + ) ) assertTrue(mCountDownLatch.await(TestUtils.DEFAULT_TIMEOUT_MS.toLong(), MILLISECONDS)) @@ -707,7 +770,12 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { mCountDownLatch = CountDownLatch(1) mDispatcher.dispatch( - WCProductActionBuilder.newAddedProductAction(RemoteAddProductPayload(sSite, productModel)) + WCProductActionBuilder.newAddedProductAction( + RemoteAddProductPayload( + sSite, + productModel + ) + ) ) assertTrue(mCountDownLatch.await(TestUtils.DEFAULT_TIMEOUT_MS.toLong(), MILLISECONDS)) } @@ -745,6 +813,7 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { assertEquals(TestEvent.FETCHED_PRODUCTS, nextEvent) mCountDownLatch.countDown() } + else -> throw AssertionError("Unexpected cause of change: " + event.causeOfChange) } } @@ -809,7 +878,7 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { fun onProductShippingClassesChanged(event: OnProductShippingClassesChanged) { event.error?.let { throw AssertionError( - "OnProductShippingClassesChanged has unexpected error: ${it.type}, ${it.message}" + "OnProductShippingClassesChanged has unexpected error: ${it.type}, ${it.message}" ) } @@ -820,10 +889,12 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { assertEquals(TestEvent.FETCHED_SINGLE_PRODUCT_SHIPPING_CLASS, nextEvent) mCountDownLatch.countDown() } + WCProductAction.FETCH_PRODUCT_SHIPPING_CLASS_LIST -> { assertEquals(TestEvent.FETCHED_PRODUCT_SHIPPING_CLASS_LIST, nextEvent) mCountDownLatch.countDown() } + else -> throw AssertionError("Unexpected cause of change: " + event.causeOfChange) } } @@ -842,10 +913,12 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { assertEquals(TestEvent.FETCH_PRODUCT_CATEGORIES, nextEvent) mCountDownLatch.countDown() } + WCProductAction.ADDED_PRODUCT_CATEGORY -> { assertEquals(TestEvent.ADDED_PRODUCT_CATEGORY, nextEvent) mCountDownLatch.countDown() } + else -> throw AssertionError("Unexpected cause of change: " + event.causeOfChange) } } @@ -855,7 +928,7 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { fun onProductTagChanged(event: OnProductTagChanged) { event.error?.let { throw AssertionError( - "OnProductTagChanged has unexpected error: ${it.type}, ${it.message}" + "OnProductTagChanged has unexpected error: ${it.type}, ${it.message}" ) } @@ -866,10 +939,12 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { assertEquals(TestEvent.FETCHED_PRODUCT_TAGS, nextEvent) mCountDownLatch.countDown() } + WCProductAction.ADDED_PRODUCT_TAGS -> { assertEquals(TestEvent.ADDED_PRODUCT_TAGS, nextEvent) mCountDownLatch.countDown() } + else -> throw AssertionError("Unexpected cause of change: " + event.causeOfChange) } } @@ -889,6 +964,7 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { assertEquals(event.remoteProductId, productModel.remoteProductId) mCountDownLatch.countDown() } + else -> throw AssertionError("Unexpected cause of change: " + event.causeOfChange) } } diff --git a/example/src/main/java/org/wordpress/android/fluxc/example/ui/products/WooProductsFragment.kt b/example/src/main/java/org/wordpress/android/fluxc/example/ui/products/WooProductsFragment.kt index b35341618d..b9a0660489 100644 --- a/example/src/main/java/org/wordpress/android/fluxc/example/ui/products/WooProductsFragment.kt +++ b/example/src/main/java/org/wordpress/android/fluxc/example/ui/products/WooProductsFragment.kt @@ -307,7 +307,8 @@ class WooProductsFragment : StoreSelectingFragment() { FetchProductReviewsPayload( site, productIds = listOf(remoteProductId) - ) + ), + deletePreviouslyCachedReviews = false ) prependToLog("Fetched ${result.rowsAffected} product reviews") } @@ -321,7 +322,10 @@ class WooProductsFragment : StoreSelectingFragment() { coroutineScope.launch { prependToLog("Submitting request to fetch product reviews for site ${site.id}") val payload = FetchProductReviewsPayload(site) - val result = wcProductStore.fetchProductReviews(payload) + val result = wcProductStore.fetchProductReviews( + payload, + deletePreviouslyCachedReviews = false + ) prependToLog("Fetched ${result.rowsAffected} product reviews") } } diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCProductStore.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCProductStore.kt index 96adf10595..265aa8be93 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCProductStore.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCProductStore.kt @@ -1222,7 +1222,7 @@ class WCProductStore @Inject constructor( suspend fun fetchProductReviews( payload: FetchProductReviewsPayload, - deletePreviouslyCachedReviews: Boolean = true + deletePreviouslyCachedReviews: Boolean ): OnProductReviewChanged { return coroutineEngine.withDefaultContext(API, this, "fetchProductReviews") { val response = with(payload) { From e44931a96fcb698a89a5c639de080de8fe8d0864 Mon Sep 17 00:00:00 2001 From: jorgemucientesfayos Date: Tue, 19 Sep 2023 12:15:52 +0200 Subject: [PATCH 51/55] Revert code formatting change to fix checkstyle --- .../android/fluxc/release/ReleaseStack_WCProductTest.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/example/src/androidTest/java/org/wordpress/android/fluxc/release/ReleaseStack_WCProductTest.kt b/example/src/androidTest/java/org/wordpress/android/fluxc/release/ReleaseStack_WCProductTest.kt index c78de558e4..9b14fa0800 100644 --- a/example/src/androidTest/java/org/wordpress/android/fluxc/release/ReleaseStack_WCProductTest.kt +++ b/example/src/androidTest/java/org/wordpress/android/fluxc/release/ReleaseStack_WCProductTest.kt @@ -82,8 +82,7 @@ class ReleaseStack_WCProductTest : ReleaseStack_WCBase() { @Inject internal lateinit var productStore: WCProductStore - @Inject - internal lateinit var mediaStore: MediaStore // must be injected for onMediaListFetched() + @Inject internal lateinit var mediaStore: MediaStore // must be injected for onMediaListFetched() private var nextEvent: TestEvent = TestEvent.NONE private val productModel = WCProductModel(8).apply { From 0c191a93520e2c3ee4194c91213b0f1751c89780 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Tue, 19 Sep 2023 15:23:04 +0100 Subject: [PATCH 52/55] Add a comment explaining the logic of fetchSites --- .../fluxc/network/rest/wpcom/site/SiteRestClient.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/site/SiteRestClient.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/site/SiteRestClient.kt index 9d14626d9b..8d440f4208 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/site/SiteRestClient.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/site/SiteRestClient.kt @@ -132,6 +132,14 @@ class SiteRestClient @Inject constructor( val site: SiteModel? = null ) : Payload() + /** + * Fetches the user's sites from WPCom. + * Since the V1.2 endpoint doesn't return the plan features, we will handle the fetch by following two + * different approaches: + * 1. If we don't need any filtering, then we'll simply use the v1.1 endpoint which includes the features. + * 2. If we have some filters, then we'll send two requests: the first one to the v1.2 endpoint to fetch sites + * And the second one to the /me/sites/features to fetch the features separately, the combine the results. + */ @Suppress("ComplexMethod") suspend fun fetchSites(filters: List, filterJetpackConnectedPackageSite: Boolean): SitesModel { val useV2Endpoint = filters.isNotEmpty() @@ -140,7 +148,6 @@ class SiteRestClient @Inject constructor( val response = wpComGsonRequestBuilder.syncGetRequest(this, url, params, SitesResponse::class.java) val siteFeatures = if (useV2Endpoint) { - // The v1.2 version doesn't include the plan features, so use the specific endpoint to fetch them separately fetchSitesFeatures().let { if (it is Error) { val result = SitesModel() From fee18fa785e587791d4f35304472d05f3c2ecbe5 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 26 Sep 2023 12:34:21 +0400 Subject: [PATCH 53/55] Inserting customers without update --- .../android/fluxc/persistence/CustomerSqlUtils.kt | 8 +++++++- .../android/fluxc/store/WCCustomerStore.kt | 14 +++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/CustomerSqlUtils.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/CustomerSqlUtils.kt index 26fb079c2e..bdb603e5ce 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/CustomerSqlUtils.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/CustomerSqlUtils.kt @@ -65,7 +65,13 @@ object CustomerSqlUtils { } fun insertOrUpdateCustomers(customers: List): Int { - return customers.sumBy { insertOrUpdateCustomer(it) } + return customers.sumOf { insertOrUpdateCustomer(it) } + } + + fun insertCustomers(customers: List) { + customers.forEach { + WellSql.insert(it).asSingleTransaction(true).execute() + } } // endregion diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCCustomerStore.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCCustomerStore.kt index d46949e04a..63693e8b82 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCCustomerStore.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCCustomerStore.kt @@ -42,6 +42,14 @@ class WCCustomerStore @Inject constructor( fun getCustomerByRemoteIds(site: SiteModel, remoteCustomerId: List) = CustomerSqlUtils.getCustomerByRemoteIds(site, remoteCustomerId) + fun saveCustomers(customers: List) { + CustomerSqlUtils.insertCustomers(customers) + } + + fun deleteCustomersForSite(site: SiteModel) { + CustomerSqlUtils.deleteCustomersForSite(site) + } + /** * returns a customer with provided remote id */ @@ -201,11 +209,7 @@ class WCCustomerStore @Inject constructor( WooResult(response.error) } response.result != null -> { - val customers = response.result.map { mapper.mapToModel(site, it) } - if (page == 1) CustomerSqlUtils.deleteCustomersForSite(site) - CustomerSqlUtils.insertOrUpdateCustomers(customers) - - WooResult(customers) + WooResult(response.result.map { mapper.mapToModel(site, it) }) } else -> WooResult(WooError(GENERIC_ERROR, UNKNOWN)) } From 1545487eb0f81865cdd849586b9a1c4d66b7c5e7 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 26 Sep 2023 15:28:01 +0400 Subject: [PATCH 54/55] Removed test on the removed code --- .../fluxc/store/WCCustomerStoreTest.kt | 90 ------------------- 1 file changed, 90 deletions(-) diff --git a/example/src/test/java/org/wordpress/android/fluxc/store/WCCustomerStoreTest.kt b/example/src/test/java/org/wordpress/android/fluxc/store/WCCustomerStoreTest.kt index 70248c998b..eeb87f77b0 100644 --- a/example/src/test/java/org/wordpress/android/fluxc/store/WCCustomerStoreTest.kt +++ b/example/src/test/java/org/wordpress/android/fluxc/store/WCCustomerStoreTest.kt @@ -21,7 +21,6 @@ import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooErrorType.INVALID_RE import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooPayload import org.wordpress.android.fluxc.network.rest.wpcom.wc.customer.CustomerRestClient import org.wordpress.android.fluxc.network.rest.wpcom.wc.customer.dto.CustomerDTO -import org.wordpress.android.fluxc.network.rest.wpcom.wc.customer.dto.CustomerFromAnalyticsDTO import org.wordpress.android.fluxc.persistence.CustomerSqlUtils import org.wordpress.android.fluxc.persistence.WellSqlConfig import org.wordpress.android.fluxc.test @@ -395,95 +394,6 @@ class WCCustomerStoreTest { assertEquals(customerModel, result.model) } - @Test - fun `given page 1, when fetchCustomersFromAnalytics, then result deleted and stored`() = - test { - // given - val siteModelId = 1 - val siteModel = SiteModel().apply { id = siteModelId } - val customerOne: CustomerFromAnalyticsDTO = mock() - val customerTwo: CustomerFromAnalyticsDTO = mock() - val response = arrayOf(customerOne, customerTwo) - whenever( - restClient.fetchCustomersFromAnalytics( - siteModel, - page = 1, - pageSize = 25 - ) - ).thenReturn(WooPayload(response)) - val modelOne = WCCustomerModel().apply { - remoteCustomerId = 1L - localSiteId = siteModelId - } - val modelTwo = WCCustomerModel().apply { - remoteCustomerId = 2L - localSiteId = siteModelId - } - whenever(mapper.mapToModel(siteModel, customerOne)).thenReturn(modelOne) - whenever(mapper.mapToModel(siteModel, customerTwo)).thenReturn(modelTwo) - - // when - val result = store.fetchCustomersFromAnalytics(siteModel, 1) - - // then - assertThat(result.isError).isFalse - assertThat(result.model).isEqualTo(listOf(modelOne, modelTwo)) - assertThat(CustomerSqlUtils.getCustomersForSite(siteModel)).isEqualTo( - listOf(modelOne, modelTwo) - ) - } - - @Test - fun `given page 1 then page 2, when fetchCustomersFromAnalytics, then both result stored`() = - test { - // given - val siteModelId = 1 - val siteModel = SiteModel().apply { id = siteModelId } - val customerOne: CustomerFromAnalyticsDTO = mock() - val customerTwo: CustomerFromAnalyticsDTO = mock() - val response = arrayOf(customerOne, customerTwo) - whenever( - restClient.fetchCustomersFromAnalytics( - siteModel, - page = 1, - pageSize = 25 - ) - ).thenReturn(WooPayload(response)) - whenever( - restClient.fetchCustomersFromAnalytics( - siteModel, - page = 2, - pageSize = 25 - ) - ).thenReturn(WooPayload(response)) - val modelOne = WCCustomerModel().apply { - remoteCustomerId = 1L - localSiteId = siteModelId - } - val modelTwo = WCCustomerModel().apply { - remoteCustomerId = 2L - localSiteId = siteModelId - } - whenever(mapper.mapToModel(siteModel, customerOne)).thenReturn(modelOne) - whenever(mapper.mapToModel(siteModel, customerTwo)).thenReturn(modelTwo) - - // when - val result = store.fetchCustomersFromAnalytics(siteModel, 1) - val result2 = store.fetchCustomersFromAnalytics(siteModel, 2) - - // then - assertThat(result.isError).isFalse - assertThat(result.model).isEqualTo(listOf(modelOne, modelTwo)) - assertThat(CustomerSqlUtils.getCustomersForSite(siteModel)).isEqualTo( - listOf(modelOne, modelTwo) - ) - assertThat(result2.isError).isFalse - assertThat(result2.model).isEqualTo(listOf(modelOne, modelTwo)) - assertThat(CustomerSqlUtils.getCustomersForSite(siteModel)).isEqualTo( - listOf(modelOne, modelTwo) - ) - } - @Test fun `given error, when fetchCustomersFromAnalytics, then nothing is stored and error`() = test { From 75d3cdfb7942be7555d57901e106af438830a7c1 Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Wed, 27 Sep 2023 13:16:38 +0100 Subject: [PATCH 55/55] REST API: Use the user's entered URL when persisting the site When the users edit the WordPress URL in the settings or using some plugins, the returned URL in the API response matches the new value, and not what the user entered, and this causes a mismatch later during the login flow. --- .../fluxc/network/rest/wpapi/site/SiteWPAPIRestClient.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpapi/site/SiteWPAPIRestClient.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpapi/site/SiteWPAPIRestClient.kt index 39c224ad27..2443f527f5 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpapi/site/SiteWPAPIRestClient.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpapi/site/SiteWPAPIRestClient.kt @@ -72,7 +72,7 @@ class SiteWPAPIRestClient @Inject constructor( } wpApiRestUrl = discoveredWpApiUrl - this.url = response?.url ?: cleanedUrl.replaceBefore("://", urlScheme) + this.url = cleanedUrl.replaceBefore("://", urlScheme) this.username = payload.username this.password = payload.password }