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) } 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..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 @@ -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 taxRateDao = 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, + taxRateDao ) // Insert the site into the db so it's available later when fetching tax classes @@ -105,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/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 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" } 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..54dc8ae5ce --- /dev/null +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/taxes/TaxRateEntity.kt @@ -0,0 +1,21 @@ +package org.wordpress.android.fluxc.model.taxes + +import androidx.room.Entity +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, + 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, +) 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..6b75b7fb94 --- /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 ( + val id: Long, + val country: String?, + val state: String?, + @SerializedName("postcode") val postCode: String?, + val city: String?, + @SerializedName("postcodes") val postCodes: List?, + 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 = + TaxRateEntity( + id = RemoteId(id), + localSiteId = localSiteId, + country = country, + state = state, + postcode = postCode, + city = city, + rate = rate, + name = name, + taxClass = taxClass, + ) +} + + 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, - ) } 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( 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..45aa43dbd3 --- /dev/null +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/dao/TaxRateDao.kt @@ -0,0 +1,31 @@ +package org.wordpress.android.fluxc.persistence.dao + +import androidx.room.Dao +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 + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertOrUpdate(taxRate: TaxRateEntity): Long + + @Query("DELETE FROM TaxRate WHERE localSiteId = :localSiteId") + suspend fun deleteAll(localSiteId: LocalId) + + @Transaction + @Query("SELECT * FROM TaxRate WHERE localSiteId = :localSiteId AND id = :taxRateId") + suspend fun getTaxRate(localSiteId: LocalId, taxRateId: RemoteId): 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 d39693b0fb..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 @@ -1,17 +1,23 @@ 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 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 org.wordpress.android.util.AppLog.T.API import javax.inject.Inject import javax.inject.Singleton @@ -19,21 +25,28 @@ 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, ) { + companion object { + const val DEFAULT_PAGE_SIZE = 100 + const val DEFAULT_PAGE = 1 + } + /** * 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") { + return coroutineEngine.withDefaultContext(API, this, "fetchTaxClassList") { val response = restClient.fetchTaxClassList(site) return@withDefaultContext when { response.isError -> { WooResult(response.error) } + response.result != null -> { val taxClassModels = response.result.map { mapper.map(it).apply { localSiteId = site.id } @@ -44,20 +57,47 @@ class WCTaxStore @Inject constructor( WCTaxSqlUtils.insertOrUpdateTaxClasses(taxClassModels) WooResult(taxClassModels) } + else -> WooResult(WooError(GENERIC_ERROR, UNKNOWN)) } } } + + /** + * 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 -> WooResult(response.result.toList()) - else -> WooResult(WooError(GENERIC_ERROR, UNKNOWN)) + page: Int = DEFAULT_PAGE, + pageSize: Int = DEFAULT_PAGE_SIZE + ): WooResult { + 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) } + + val canLoadMore = response.result.size == pageSize + WooResult(canLoadMore) + } + + else -> WooResult(WooError(GENERIC_ERROR, UNKNOWN)) + } } } + + @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())) + } + + suspend fun getTaxRate(site: SiteModel, taxRateId: Long) = + taxRateDao.getTaxRate(site.localId(), RemoteId(taxRateId)) }