diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/OrderMapper.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/OrderMapper.kt index b5b9ff15e62a..4c77008a036e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/model/OrderMapper.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/model/OrderMapper.kt @@ -7,10 +7,8 @@ import com.woocommerce.android.util.DateUtils import com.woocommerce.android.util.StringUtils import org.wordpress.android.fluxc.model.metadata.WCMetaData import org.wordpress.android.fluxc.model.metadata.get -import org.wordpress.android.fluxc.model.order.FeeLine import org.wordpress.android.fluxc.model.order.FeeLineTaxStatus import org.wordpress.android.fluxc.model.order.OrderAddress -import org.wordpress.android.fluxc.model.order.ShippingLine import org.wordpress.android.fluxc.model.order.TaxLine import org.wordpress.android.fluxc.model.order.WCLineTaxEntry import org.wordpress.android.fluxc.network.rest.wpcom.wc.order.OrderMappingConst.CHARGE_ID_KEY diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/BookingMapper.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/BookingMapper.kt index 0f060824f6ce..3ac1da045fa5 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/BookingMapper.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/BookingMapper.kt @@ -2,10 +2,12 @@ package com.woocommerce.android.ui.bookings import com.woocommerce.android.ui.bookings.compose.BookingAppointmentDetailsModel import com.woocommerce.android.ui.bookings.compose.BookingAttendanceStatus +import com.woocommerce.android.ui.bookings.compose.BookingCustomerDetailsModel import com.woocommerce.android.ui.bookings.compose.BookingStatus import com.woocommerce.android.ui.bookings.compose.BookingSummaryModel import com.woocommerce.android.ui.bookings.list.BookingListItem import com.woocommerce.android.util.CurrencyFormatter +import org.wordpress.android.fluxc.network.rest.wpcom.wc.bookings.BookingCustomerInfo import org.wordpress.android.fluxc.persistence.entity.BookingEntity import java.time.Duration import java.time.ZoneOffset @@ -29,9 +31,8 @@ class BookingMapper @Inject constructor( fun Booking.toBookingSummaryModel(): BookingSummaryModel { return BookingSummaryModel( date = summaryDateFormatter.format(start), - // TODO replace mocked values when product and customer data are available - name = "Women’s Haircut", - customerName = "Margarita Nikolaevna", + name = order.productInfo?.name ?: "-", + customerName = order.customerInfo?.fullName(), attendanceStatus = BookingAttendanceStatus.BOOKED, status = status.toUiModel() ) @@ -57,6 +58,22 @@ class BookingMapper @Inject constructor( ) } + fun BookingCustomerInfo?.toCustomerDetailsModel(): BookingCustomerDetailsModel { + if (this == null) return BookingCustomerDetailsModel.EMPTY + + return BookingCustomerDetailsModel( + name = fullName(), + email = billingEmail, + phone = billingPhone, + billingAddressLines = listOfNotNull( + billingAddress1, + billingAddress2, + listOfNotNull(billingCity, billingState, billingPostcode).takeIf { it.isNotEmpty() }?.joinToString(" "), + billingCountry + ) + ) + } + private fun BookingEntity.Status.toUiModel(): BookingStatus = when (this) { BookingEntity.Status.Paid -> BookingStatus.Paid BookingEntity.Status.PendingConfirmation -> BookingStatus.PendingConfirmation @@ -66,4 +83,8 @@ class BookingMapper @Inject constructor( BookingEntity.Status.Unpaid -> BookingStatus.Unpaid is BookingEntity.Status.Unknown -> BookingStatus.Unknown(this.key) } + + private fun BookingCustomerInfo.fullName(): String? { + return "${billingFirstName.orEmpty()} ${billingLastName.orEmpty()}".trim().ifEmpty { null } + } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/compose/BookingCustomerDetails.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/compose/BookingCustomerDetails.kt index 89c0e2c675f3..99762641094c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/compose/BookingCustomerDetails.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/compose/BookingCustomerDetails.kt @@ -45,52 +45,58 @@ fun BookingCustomerDetails( .background(color = MaterialTheme.colorScheme.surfaceContainer) ) { HorizontalDivider(thickness = 0.5.dp) - CustomerDetailsRow(value = model.name) - CustomerDetailsRow( - value = model.email, - trailingIcon = { - Icon( - painter = painterResource(R.drawable.ic_email), - contentDescription = stringResource(id = R.string.booking_customer_label_email), - tint = MaterialTheme.colorScheme.primary - ) - }, - modifier = Modifier.clickable { - ActivityUtils.sendEmail(context, model.email) - } - ) - CustomerDetailsRow( - value = model.phone, - trailingIcon = { - Box { + CustomerDetailsRow(value = model.name ?: stringResource(R.string.orderdetail_customer_name_default)) + model.email?.let { email -> + CustomerDetailsRow( + value = email, + trailingIcon = { Icon( - painter = painterResource(R.drawable.ic_menu_more_vert), - contentDescription = stringResource(id = R.string.booking_customer_label_phone), + painter = painterResource(R.drawable.ic_email), + contentDescription = stringResource(id = R.string.booking_customer_label_email), tint = MaterialTheme.colorScheme.primary ) - ContactDropdownMenu( - expanded = phoneMenuExpanded, - phone = model.phone, - onDismissRequest = { phoneMenuExpanded = false } + }, + modifier = Modifier.clickable { + ActivityUtils.sendEmail(context, email) + } + ) + } + model.phone?.let { phone -> + CustomerDetailsRow( + value = phone, + trailingIcon = { + Box { + Icon( + painter = painterResource(R.drawable.ic_menu_more_vert), + contentDescription = stringResource(id = R.string.booking_customer_label_phone), + tint = MaterialTheme.colorScheme.primary + ) + ContactDropdownMenu( + expanded = phoneMenuExpanded, + phone = phone, + onDismissRequest = { phoneMenuExpanded = false } + ) + } + }, + modifier = Modifier.clickable { phoneMenuExpanded = true } + ) + } + if (model.billingAddressLines.isNotEmpty()) { + Column( + modifier = Modifier + .padding(vertical = 12.dp, horizontal = 16.dp) + ) { + BookingDetailsLabel(label = R.string.booking_billing_address_label) + model.billingAddressLines.forEach { line -> + Text( + text = line, + style = MaterialTheme.typography.labelLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant, ) } - }, - modifier = Modifier.clickable { phoneMenuExpanded = true } - ) - Column( - modifier = Modifier - .padding(vertical = 12.dp, horizontal = 16.dp) - ) { - BookingDetailsLabel(label = R.string.booking_billing_address_label) - model.billingAddressLines.forEach { line -> - Text( - text = line, - style = MaterialTheme.typography.labelLarge, - color = MaterialTheme.colorScheme.onSurfaceVariant, - ) } + HorizontalDivider(thickness = 0.5.dp) } - HorizontalDivider(thickness = 0.5.dp) } } } @@ -139,11 +145,20 @@ private fun CustomerDetailsRow( } data class BookingCustomerDetailsModel( - val name: String, - val email: String, - val phone: String, + val name: String?, + val email: String?, + val phone: String?, val billingAddressLines: List, -) +) { + companion object { + val EMPTY = BookingCustomerDetailsModel( + name = null, + email = null, + phone = null, + billingAddressLines = emptyList() + ) + } +} @LightDarkThemePreviews @Composable diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/compose/BookingSummary.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/compose/BookingSummary.kt index 75aaade05013..ad3a94e520b4 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/compose/BookingSummary.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/compose/BookingSummary.kt @@ -13,10 +13,12 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import com.woocommerce.android.R import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground @Composable @@ -44,7 +46,7 @@ fun BookingSummary( style = MaterialTheme.typography.labelMedium.copy(fontSize = 13.sp), ) Text( - text = model.customerName, + text = model.customerName ?: stringResource(R.string.orderdetail_customer_name_default), color = MaterialTheme.colorScheme.onSurfaceVariant, style = MaterialTheme.typography.labelMedium.copy(fontSize = 13.sp), ) @@ -67,7 +69,7 @@ fun BookingSummary( data class BookingSummaryModel( val date: String, val name: String, - val customerName: String, + val customerName: String?, val attendanceStatus: BookingAttendanceStatus, val status: BookingStatus, ) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/details/BookingDetailsViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/details/BookingDetailsViewModel.kt index 82e311325305..fb0531a9b9a1 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/details/BookingDetailsViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/details/BookingDetailsViewModel.kt @@ -8,7 +8,6 @@ import com.woocommerce.android.ui.bookings.Booking import com.woocommerce.android.ui.bookings.BookingMapper import com.woocommerce.android.ui.bookings.BookingsRepository import com.woocommerce.android.ui.bookings.compose.BookingAttendanceStatus -import com.woocommerce.android.ui.bookings.compose.BookingCustomerDetailsModel import com.woocommerce.android.ui.bookings.compose.BookingPaymentDetailsModel import com.woocommerce.android.viewmodel.ResourceProvider import com.woocommerce.android.viewmodel.ScopedViewModel @@ -70,16 +69,7 @@ class BookingDetailsViewModel @Inject constructor( } }, bookingsAppointmentDetails = booking.toAppointmentDetailsModel(), - bookingCustomerDetails = BookingCustomerDetailsModel( - name = "Margarita Nikolaevna", - email = "margarita@example.com", - phone = "+1 555-123-4567", - billingAddressLines = listOf( - "238 Willow Creek Drive", - "Montgomery AL 36109", - "United States" - ) - ), + bookingCustomerDetails = booking.order.customerInfo.toCustomerDetailsModel(), bookingPaymentDetails = BookingPaymentDetailsModel( service = "$55.00", tax = "$4.50", diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/bookings/BookingMapperTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/bookings/BookingMapperTest.kt index 473466612279..c1499c9b320d 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/bookings/BookingMapperTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/bookings/BookingMapperTest.kt @@ -12,6 +12,9 @@ import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.whenever import org.wordpress.android.fluxc.model.LocalOrRemoteId +import org.wordpress.android.fluxc.network.rest.wpcom.wc.bookings.BookingCustomerInfo +import org.wordpress.android.fluxc.network.rest.wpcom.wc.bookings.BookingOrderInfo +import org.wordpress.android.fluxc.network.rest.wpcom.wc.bookings.BookingProductInfo import org.wordpress.android.fluxc.persistence.entity.BookingEntity import java.time.Duration import java.time.Instant @@ -52,8 +55,9 @@ class BookingMapperTest : BaseUnitTest() { // THEN assertThat(model.date).isEqualTo(expectedDate) - assertThat(model.name).isEqualTo("Women’s Haircut") - assertThat(model.customerName).isEqualTo("Margarita Nikolaevna") + assertThat(model.name).isEqualTo(booking.order.productInfo?.name) + assertThat(model.customerName) + .isEqualTo("${booking.order.customerInfo?.billingFirstName} ${booking.order.customerInfo?.billingLastName}") assertThat(model.attendanceStatus).isEqualTo(BookingAttendanceStatus.BOOKED) assertThat(model.status).isEqualTo(BookingStatus.Confirmed) } @@ -131,7 +135,15 @@ class BookingMapperTest : BaseUnitTest() { orderItemId = 1L, parentId = 0L, personCounts = listOf(1L), - localTimezone = "UTC" + localTimezone = "UTC", + order = BookingOrderInfo( + status = "completed", + productInfo = BookingProductInfo(name = "Women’s Haircut"), + customerInfo = BookingCustomerInfo( + billingFirstName = "Margarita", + billingLastName = "Nikolaevna" + ) + ) ) } } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/bookings/details/BookingDetailsViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/bookings/details/BookingDetailsViewModelTest.kt index 072d44f4e043..ef40a8fc76ef 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/bookings/details/BookingDetailsViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/bookings/details/BookingDetailsViewModelTest.kt @@ -21,6 +21,7 @@ import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.whenever import org.wordpress.android.fluxc.model.LocalOrRemoteId +import org.wordpress.android.fluxc.network.rest.wpcom.wc.bookings.BookingOrderInfo import org.wordpress.android.fluxc.persistence.entity.BookingEntity import java.time.Duration import java.time.Instant @@ -127,7 +128,8 @@ class BookingDetailsViewModelTest : BaseUnitTest() { orderItemId = 1L, parentId = 0L, personCounts = listOf(1L), - localTimezone = "" + localTimezone = "", + order = BookingOrderInfo() ) } } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/bookings/list/BookingListHandlerTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/bookings/list/BookingListHandlerTest.kt index 5bc23fb55ebe..71d958f9b7b6 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/bookings/list/BookingListHandlerTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/bookings/list/BookingListHandlerTest.kt @@ -23,6 +23,7 @@ import org.mockito.kotlin.never import org.mockito.kotlin.verify import org.wordpress.android.fluxc.model.LocalOrRemoteId.LocalId import org.wordpress.android.fluxc.model.LocalOrRemoteId.RemoteId +import org.wordpress.android.fluxc.network.rest.wpcom.wc.bookings.BookingOrderInfo import org.wordpress.android.fluxc.persistence.entity.BookingEntity import java.time.Duration import java.time.Instant @@ -220,6 +221,7 @@ class BookingListHandlerTest : BaseUnitTest() { orderItemId = 1L, parentId = 0L, personCounts = listOf(1L), - localTimezone = "" + localTimezone = "", + order = BookingOrderInfo() ) } diff --git a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/bookings/list/BookingListViewModelTest.kt b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/bookings/list/BookingListViewModelTest.kt index df21cf9fbeab..7379801b906b 100644 --- a/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/bookings/list/BookingListViewModelTest.kt +++ b/WooCommerce/src/test/kotlin/com/woocommerce/android/ui/bookings/list/BookingListViewModelTest.kt @@ -25,6 +25,7 @@ import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import org.wordpress.android.fluxc.model.LocalOrRemoteId import org.wordpress.android.fluxc.network.rest.wpcom.wc.bookings.BookingFilters +import org.wordpress.android.fluxc.network.rest.wpcom.wc.bookings.BookingOrderInfo import org.wordpress.android.fluxc.network.rest.wpcom.wc.bookings.BookingsFilterOption import org.wordpress.android.fluxc.persistence.entity.BookingEntity import java.time.Clock @@ -345,7 +346,8 @@ class BookingListViewModelTest : BaseUnitTest() { orderItemId = 1L, parentId = 0L, personCounts = listOf(1L), - localTimezone = "" + localTimezone = "", + order = BookingOrderInfo() ) } } diff --git a/libs/fluxc-plugin/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/68.json b/libs/fluxc-plugin/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/68.json new file mode 100644 index 000000000000..fc75bbf09a6c --- /dev/null +++ b/libs/fluxc-plugin/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/68.json @@ -0,0 +1,4224 @@ +{ + "formatVersion": 1, + "database": { + "version": 68, + "identityHash": "d5062b5e8fcdf91affe375df7ef6d4fd", + "entities": [ + { + "tableName": "AddonEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`addonLocalId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `globalGroupLocalId` INTEGER, `productRemoteId` INTEGER, `localSiteId` INTEGER, `type` TEXT NOT NULL, `display` TEXT, `name` TEXT NOT NULL, `titleFormat` TEXT NOT NULL, `description` TEXT, `required` INTEGER NOT NULL, `position` INTEGER NOT NULL, `restrictions` TEXT, `priceType` TEXT, `price` TEXT, `min` INTEGER, `max` INTEGER, FOREIGN KEY(`globalGroupLocalId`) REFERENCES `GlobalAddonGroupEntity`(`globalGroupLocalId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "addonLocalId", + "columnName": "addonLocalId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "globalGroupLocalId", + "columnName": "globalGroupLocalId", + "affinity": "INTEGER" + }, + { + "fieldPath": "productRemoteId", + "columnName": "productRemoteId", + "affinity": "INTEGER" + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER" + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "display", + "columnName": "display", + "affinity": "TEXT" + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "titleFormat", + "columnName": "titleFormat", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT" + }, + { + "fieldPath": "required", + "columnName": "required", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "position", + "columnName": "position", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "restrictions", + "columnName": "restrictions", + "affinity": "TEXT" + }, + { + "fieldPath": "priceType", + "columnName": "priceType", + "affinity": "TEXT" + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "TEXT" + }, + { + "fieldPath": "min", + "columnName": "min", + "affinity": "INTEGER" + }, + { + "fieldPath": "max", + "columnName": "max", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "addonLocalId" + ] + }, + "indices": [ + { + "name": "index_AddonEntity_globalGroupLocalId", + "unique": false, + "columnNames": [ + "globalGroupLocalId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_AddonEntity_globalGroupLocalId` ON `${TABLE_NAME}` (`globalGroupLocalId`)" + } + ], + "foreignKeys": [ + { + "table": "GlobalAddonGroupEntity", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "globalGroupLocalId" + ], + "referencedColumns": [ + "globalGroupLocalId" + ] + } + ] + }, + { + "tableName": "AddonOptionEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`addonOptionLocalId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `addonLocalId` INTEGER NOT NULL, `priceType` TEXT NOT NULL, `label` TEXT, `price` TEXT, `image` TEXT, FOREIGN KEY(`addonLocalId`) REFERENCES `AddonEntity`(`addonLocalId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "addonOptionLocalId", + "columnName": "addonOptionLocalId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "addonLocalId", + "columnName": "addonLocalId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "priceType", + "columnName": "priceType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "label", + "columnName": "label", + "affinity": "TEXT" + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "TEXT" + }, + { + "fieldPath": "image", + "columnName": "image", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "addonOptionLocalId" + ] + }, + "indices": [ + { + "name": "index_AddonOptionEntity_addonLocalId", + "unique": false, + "columnNames": [ + "addonLocalId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_AddonOptionEntity_addonLocalId` ON `${TABLE_NAME}` (`addonLocalId`)" + } + ], + "foreignKeys": [ + { + "table": "AddonEntity", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "addonLocalId" + ], + "referencedColumns": [ + "addonLocalId" + ] + } + ] + }, + { + "tableName": "Coupons", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `localSiteId` INTEGER NOT NULL, `code` TEXT, `amount` TEXT, `dateCreated` TEXT, `dateCreatedGmt` TEXT, `dateModified` TEXT, `dateModifiedGmt` TEXT, `discountType` TEXT, `description` TEXT, `dateExpires` TEXT, `dateExpiresGmt` TEXT, `usageCount` INTEGER, `isForIndividualUse` INTEGER, `usageLimit` INTEGER, `usageLimitPerUser` INTEGER, `limitUsageToXItems` INTEGER, `isShippingFree` INTEGER, `areSaleItemsExcluded` INTEGER, `minimumAmount` TEXT, `maximumAmount` TEXT, `includedProductIds` TEXT, `excludedProductIds` TEXT, `includedCategoryIds` TEXT, `excludedCategoryIds` TEXT, PRIMARY KEY(`id`, `localSiteId`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "code", + "columnName": "code", + "affinity": "TEXT" + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "TEXT" + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT" + }, + { + "fieldPath": "dateCreatedGmt", + "columnName": "dateCreatedGmt", + "affinity": "TEXT" + }, + { + "fieldPath": "dateModified", + "columnName": "dateModified", + "affinity": "TEXT" + }, + { + "fieldPath": "dateModifiedGmt", + "columnName": "dateModifiedGmt", + "affinity": "TEXT" + }, + { + "fieldPath": "discountType", + "columnName": "discountType", + "affinity": "TEXT" + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT" + }, + { + "fieldPath": "dateExpires", + "columnName": "dateExpires", + "affinity": "TEXT" + }, + { + "fieldPath": "dateExpiresGmt", + "columnName": "dateExpiresGmt", + "affinity": "TEXT" + }, + { + "fieldPath": "usageCount", + "columnName": "usageCount", + "affinity": "INTEGER" + }, + { + "fieldPath": "isForIndividualUse", + "columnName": "isForIndividualUse", + "affinity": "INTEGER" + }, + { + "fieldPath": "usageLimit", + "columnName": "usageLimit", + "affinity": "INTEGER" + }, + { + "fieldPath": "usageLimitPerUser", + "columnName": "usageLimitPerUser", + "affinity": "INTEGER" + }, + { + "fieldPath": "limitUsageToXItems", + "columnName": "limitUsageToXItems", + "affinity": "INTEGER" + }, + { + "fieldPath": "isShippingFree", + "columnName": "isShippingFree", + "affinity": "INTEGER" + }, + { + "fieldPath": "areSaleItemsExcluded", + "columnName": "areSaleItemsExcluded", + "affinity": "INTEGER" + }, + { + "fieldPath": "minimumAmount", + "columnName": "minimumAmount", + "affinity": "TEXT" + }, + { + "fieldPath": "maximumAmount", + "columnName": "maximumAmount", + "affinity": "TEXT" + }, + { + "fieldPath": "includedProductIds", + "columnName": "includedProductIds", + "affinity": "TEXT" + }, + { + "fieldPath": "excludedProductIds", + "columnName": "excludedProductIds", + "affinity": "TEXT" + }, + { + "fieldPath": "includedCategoryIds", + "columnName": "includedCategoryIds", + "affinity": "TEXT" + }, + { + "fieldPath": "excludedCategoryIds", + "columnName": "excludedCategoryIds", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id", + "localSiteId" + ] + } + }, + { + "tableName": "CouponEmails", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`couponId` INTEGER NOT NULL, `localSiteId` INTEGER NOT NULL, `email` TEXT NOT NULL, PRIMARY KEY(`couponId`, `localSiteId`, `email`), FOREIGN KEY(`couponId`, `localSiteId`) REFERENCES `Coupons`(`id`, `localSiteId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "couponId", + "columnName": "couponId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "couponId", + "localSiteId", + "email" + ] + }, + "foreignKeys": [ + { + "table": "Coupons", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "couponId", + "localSiteId" + ], + "referencedColumns": [ + "id", + "localSiteId" + ] + } + ] + }, + { + "tableName": "GlobalAddonGroupEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`globalGroupLocalId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `restrictedCategoriesIds` TEXT NOT NULL, `localSiteId` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "globalGroupLocalId", + "columnName": "globalGroupLocalId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "restrictedCategoriesIds", + "columnName": "restrictedCategoriesIds", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "globalGroupLocalId" + ] + } + }, + { + "tableName": "OrderNotes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `noteId` INTEGER NOT NULL, `orderId` INTEGER NOT NULL, `dateCreated` TEXT, `note` TEXT, `author` TEXT, `isSystemNote` INTEGER NOT NULL, `isCustomerNote` INTEGER NOT NULL, PRIMARY KEY(`localSiteId`, `noteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "noteId", + "columnName": "noteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "orderId", + "columnName": "orderId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT" + }, + { + "fieldPath": "note", + "columnName": "note", + "affinity": "TEXT" + }, + { + "fieldPath": "author", + "columnName": "author", + "affinity": "TEXT" + }, + { + "fieldPath": "isSystemNote", + "columnName": "isSystemNote", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isCustomerNote", + "columnName": "isCustomerNote", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "noteId" + ] + } + }, + { + "tableName": "OrderEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `orderId` INTEGER NOT NULL, `number` TEXT NOT NULL, `status` TEXT NOT NULL, `currency` TEXT NOT NULL, `orderKey` TEXT NOT NULL, `dateCreated` TEXT NOT NULL, `dateModified` TEXT NOT NULL, `total` TEXT NOT NULL, `totalTax` TEXT NOT NULL, `shippingTotal` TEXT NOT NULL, `paymentMethod` TEXT NOT NULL, `paymentMethodTitle` TEXT NOT NULL, `datePaid` TEXT NOT NULL, `pricesIncludeTax` INTEGER NOT NULL, `customerNote` TEXT NOT NULL, `discountTotal` TEXT NOT NULL, `discountCodes` TEXT NOT NULL, `refundTotal` TEXT NOT NULL, `customerId` INTEGER NOT NULL DEFAULT 0, `billingFirstName` TEXT NOT NULL, `billingLastName` TEXT NOT NULL, `billingCompany` TEXT NOT NULL, `billingAddress1` TEXT NOT NULL, `billingAddress2` TEXT NOT NULL, `billingCity` TEXT NOT NULL, `billingState` TEXT NOT NULL, `billingPostcode` TEXT NOT NULL, `billingCountry` TEXT NOT NULL, `billingEmail` TEXT NOT NULL, `billingPhone` TEXT NOT NULL, `shippingFirstName` TEXT NOT NULL, `shippingLastName` TEXT NOT NULL, `shippingCompany` TEXT NOT NULL, `shippingAddress1` TEXT NOT NULL, `shippingAddress2` TEXT NOT NULL, `shippingCity` TEXT NOT NULL, `shippingState` TEXT NOT NULL, `shippingPostcode` TEXT NOT NULL, `shippingCountry` TEXT NOT NULL, `shippingPhone` TEXT NOT NULL, `lineItems` TEXT NOT NULL, `shippingLines` TEXT NOT NULL, `feeLines` TEXT NOT NULL, `taxLines` TEXT NOT NULL, `couponLines` TEXT NOT NULL DEFAULT '', `metaData` TEXT NOT NULL, `paymentUrl` TEXT NOT NULL DEFAULT '', `isEditable` INTEGER NOT NULL DEFAULT 1, `needsPayment` INTEGER, `needsProcessing` INTEGER, `giftCardCode` TEXT NOT NULL DEFAULT '', `giftCardAmount` TEXT NOT NULL DEFAULT '', `shippingTax` TEXT NOT NULL DEFAULT '', `createdVia` TEXT NOT NULL DEFAULT '', PRIMARY KEY(`localSiteId`, `orderId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "orderId", + "columnName": "orderId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "orderKey", + "columnName": "orderKey", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateModified", + "columnName": "dateModified", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "total", + "columnName": "total", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "totalTax", + "columnName": "totalTax", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingTotal", + "columnName": "shippingTotal", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "paymentMethod", + "columnName": "paymentMethod", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "paymentMethodTitle", + "columnName": "paymentMethodTitle", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "datePaid", + "columnName": "datePaid", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pricesIncludeTax", + "columnName": "pricesIncludeTax", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "customerNote", + "columnName": "customerNote", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "discountTotal", + "columnName": "discountTotal", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "discountCodes", + "columnName": "discountCodes", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "refundTotal", + "columnName": "refundTotal", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "customerId", + "columnName": "customerId", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "billingFirstName", + "columnName": "billingFirstName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingLastName", + "columnName": "billingLastName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingCompany", + "columnName": "billingCompany", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingAddress1", + "columnName": "billingAddress1", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingAddress2", + "columnName": "billingAddress2", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingCity", + "columnName": "billingCity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingState", + "columnName": "billingState", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingPostcode", + "columnName": "billingPostcode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingCountry", + "columnName": "billingCountry", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingEmail", + "columnName": "billingEmail", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingPhone", + "columnName": "billingPhone", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingFirstName", + "columnName": "shippingFirstName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingLastName", + "columnName": "shippingLastName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingCompany", + "columnName": "shippingCompany", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingAddress1", + "columnName": "shippingAddress1", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingAddress2", + "columnName": "shippingAddress2", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingCity", + "columnName": "shippingCity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingState", + "columnName": "shippingState", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingPostcode", + "columnName": "shippingPostcode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingCountry", + "columnName": "shippingCountry", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingPhone", + "columnName": "shippingPhone", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lineItems", + "columnName": "lineItems", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingLines", + "columnName": "shippingLines", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "feeLines", + "columnName": "feeLines", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "taxLines", + "columnName": "taxLines", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "couponLines", + "columnName": "couponLines", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "metaData", + "columnName": "metaData", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "paymentUrl", + "columnName": "paymentUrl", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "isEditable", + "columnName": "isEditable", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "1" + }, + { + "fieldPath": "needsPayment", + "columnName": "needsPayment", + "affinity": "INTEGER" + }, + { + "fieldPath": "needsProcessing", + "columnName": "needsProcessing", + "affinity": "INTEGER" + }, + { + "fieldPath": "giftCardCode", + "columnName": "giftCardCode", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "giftCardAmount", + "columnName": "giftCardAmount", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "shippingTax", + "columnName": "shippingTax", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "createdVia", + "columnName": "createdVia", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "orderId" + ] + }, + "indices": [ + { + "name": "index_OrderEntity_localSiteId_orderId", + "unique": false, + "columnNames": [ + "localSiteId", + "orderId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_OrderEntity_localSiteId_orderId` ON `${TABLE_NAME}` (`localSiteId`, `orderId`)" + } + ] + }, + { + "tableName": "RefundEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`siteId` INTEGER NOT NULL, `orderId` INTEGER NOT NULL, `refundId` INTEGER NOT NULL, `data` TEXT NOT NULL, PRIMARY KEY(`siteId`, `orderId`, `refundId`))", + "fields": [ + { + "fieldPath": "siteId", + "columnName": "siteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "orderId", + "columnName": "orderId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "refundId", + "columnName": "refundId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "data", + "columnName": "data", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "siteId", + "orderId", + "refundId" + ] + } + }, + { + "tableName": "MetaData", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `parentItemId` INTEGER NOT NULL, `key` TEXT NOT NULL, `value` TEXT NOT NULL, `type` TEXT NOT NULL DEFAULT 'ORDER', PRIMARY KEY(`localSiteId`, `parentItemId`, `id`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "parentItemId", + "columnName": "parentItemId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "'ORDER'" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "parentItemId", + "id" + ] + } + }, + { + "tableName": "InboxNotes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `remoteId` INTEGER NOT NULL, `localSiteId` INTEGER NOT NULL, `name` TEXT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `dateCreated` TEXT NOT NULL, `status` TEXT NOT NULL, `source` TEXT, `type` TEXT, `dateReminder` TEXT)", + "fields": [ + { + "fieldPath": "localId", + "columnName": "localId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "source", + "columnName": "source", + "affinity": "TEXT" + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT" + }, + { + "fieldPath": "dateReminder", + "columnName": "dateReminder", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "localId" + ] + }, + "indices": [ + { + "name": "index_InboxNotes_remoteId_localSiteId", + "unique": true, + "columnNames": [ + "remoteId", + "localSiteId" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_InboxNotes_remoteId_localSiteId` ON `${TABLE_NAME}` (`remoteId`, `localSiteId`)" + } + ] + }, + { + "tableName": "InboxNoteActions", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remoteId` INTEGER NOT NULL, `inboxNoteLocalId` INTEGER NOT NULL, `localSiteId` INTEGER NOT NULL, `name` TEXT NOT NULL, `label` TEXT NOT NULL, `url` TEXT NOT NULL, `query` TEXT, `status` TEXT, `primary` INTEGER NOT NULL, `actionedText` TEXT, PRIMARY KEY(`remoteId`, `inboxNoteLocalId`), FOREIGN KEY(`inboxNoteLocalId`) REFERENCES `InboxNotes`(`localId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "inboxNoteLocalId", + "columnName": "inboxNoteLocalId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "label", + "columnName": "label", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "query", + "columnName": "query", + "affinity": "TEXT" + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT" + }, + { + "fieldPath": "primary", + "columnName": "primary", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "actionedText", + "columnName": "actionedText", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "remoteId", + "inboxNoteLocalId" + ] + }, + "indices": [ + { + "name": "index_InboxNoteActions_inboxNoteLocalId", + "unique": false, + "columnNames": [ + "inboxNoteLocalId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_InboxNoteActions_inboxNoteLocalId` ON `${TABLE_NAME}` (`inboxNoteLocalId`)" + } + ], + "foreignKeys": [ + { + "table": "InboxNotes", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "inboxNoteLocalId" + ], + "referencedColumns": [ + "localId" + ] + } + ] + }, + { + "tableName": "TopPerformerProducts", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `datePeriod` TEXT NOT NULL, `productId` INTEGER NOT NULL, `name` TEXT NOT NULL, `imageUrl` TEXT, `quantity` INTEGER NOT NULL, `currency` TEXT NOT NULL, `total` REAL NOT NULL, `millisSinceLastUpdated` INTEGER NOT NULL, PRIMARY KEY(`datePeriod`, `productId`, `localSiteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "datePeriod", + "columnName": "datePeriod", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "productId", + "columnName": "productId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "imageUrl", + "columnName": "imageUrl", + "affinity": "TEXT" + }, + { + "fieldPath": "quantity", + "columnName": "quantity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "total", + "columnName": "total", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "millisSinceLastUpdated", + "columnName": "millisSinceLastUpdated", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "datePeriod", + "productId", + "localSiteId" + ] + } + }, + { + "tableName": "TaxBasedOnSetting", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `selectedOption` TEXT NOT NULL, PRIMARY KEY(`localSiteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "selectedOption", + "columnName": "selectedOption", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId" + ] + } + }, + { + "tableName": "TaxRate", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `localSiteId` INTEGER NOT NULL, `country` TEXT, `state` TEXT, `postcode` TEXT, `city` TEXT, `rate` TEXT, `name` TEXT, `taxClass` TEXT, PRIMARY KEY(`id`, `localSiteId`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "country", + "columnName": "country", + "affinity": "TEXT" + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT" + }, + { + "fieldPath": "postcode", + "columnName": "postcode", + "affinity": "TEXT" + }, + { + "fieldPath": "city", + "columnName": "city", + "affinity": "TEXT" + }, + { + "fieldPath": "rate", + "columnName": "rate", + "affinity": "TEXT" + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT" + }, + { + "fieldPath": "taxClass", + "columnName": "taxClass", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id", + "localSiteId" + ] + } + }, + { + "tableName": "WooPaymentsDepositsOverview", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `depositsEnabled` INTEGER, `depositsBlocked` INTEGER, `defaultCurrency` TEXT, `delayDays` INTEGER, `weeklyAnchor` TEXT, `monthlyAnchor` INTEGER, `interval` TEXT, PRIMARY KEY(`localSiteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "account.depositsEnabled", + "columnName": "depositsEnabled", + "affinity": "INTEGER" + }, + { + "fieldPath": "account.depositsBlocked", + "columnName": "depositsBlocked", + "affinity": "INTEGER" + }, + { + "fieldPath": "account.defaultCurrency", + "columnName": "defaultCurrency", + "affinity": "TEXT" + }, + { + "fieldPath": "account.depositsSchedule.delayDays", + "columnName": "delayDays", + "affinity": "INTEGER" + }, + { + "fieldPath": "account.depositsSchedule.weeklyAnchor", + "columnName": "weeklyAnchor", + "affinity": "TEXT" + }, + { + "fieldPath": "account.depositsSchedule.monthlyAnchor", + "columnName": "monthlyAnchor", + "affinity": "INTEGER" + }, + { + "fieldPath": "account.depositsSchedule.interval", + "columnName": "interval", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId" + ] + } + }, + { + "tableName": "WooPaymentsDeposits", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `localSiteId` INTEGER NOT NULL, `depositId` TEXT, `date` INTEGER, `type` TEXT, `amount` INTEGER, `status` TEXT, `bankAccount` TEXT, `currency` TEXT, `automatic` INTEGER, `fee` INTEGER, `feePercentage` REAL, `created` INTEGER, `depositType` TEXT NOT NULL, FOREIGN KEY(`localSiteId`) REFERENCES `WooPaymentsDepositsOverview`(`localSiteId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "depositId", + "columnName": "depositId", + "affinity": "TEXT" + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER" + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT" + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "INTEGER" + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT" + }, + { + "fieldPath": "bankAccount", + "columnName": "bankAccount", + "affinity": "TEXT" + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT" + }, + { + "fieldPath": "automatic", + "columnName": "automatic", + "affinity": "INTEGER" + }, + { + "fieldPath": "fee", + "columnName": "fee", + "affinity": "INTEGER" + }, + { + "fieldPath": "feePercentage", + "columnName": "feePercentage", + "affinity": "REAL" + }, + { + "fieldPath": "created", + "columnName": "created", + "affinity": "INTEGER" + }, + { + "fieldPath": "depositType", + "columnName": "depositType", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "foreignKeys": [ + { + "table": "WooPaymentsDepositsOverview", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "localSiteId" + ], + "referencedColumns": [ + "localSiteId" + ] + } + ] + }, + { + "tableName": "WooPaymentsManualDeposits", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `localSiteId` INTEGER NOT NULL, `currency` TEXT, `date` INTEGER, FOREIGN KEY(`localSiteId`) REFERENCES `WooPaymentsDepositsOverview`(`localSiteId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT" + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "foreignKeys": [ + { + "table": "WooPaymentsDepositsOverview", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "localSiteId" + ], + "referencedColumns": [ + "localSiteId" + ] + } + ] + }, + { + "tableName": "WooPaymentsBalance", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `localSiteId` INTEGER NOT NULL, `amount` INTEGER, `currency` TEXT, `fee` INTEGER, `feePercentage` REAL, `net` INTEGER, `balanceType` TEXT NOT NULL, `card` INTEGER, FOREIGN KEY(`localSiteId`) REFERENCES `WooPaymentsDepositsOverview`(`localSiteId`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "INTEGER" + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT" + }, + { + "fieldPath": "fee", + "columnName": "fee", + "affinity": "INTEGER" + }, + { + "fieldPath": "feePercentage", + "columnName": "feePercentage", + "affinity": "REAL" + }, + { + "fieldPath": "net", + "columnName": "net", + "affinity": "INTEGER" + }, + { + "fieldPath": "balanceType", + "columnName": "balanceType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sourceTypes.card", + "columnName": "card", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "foreignKeys": [ + { + "table": "WooPaymentsDepositsOverview", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "localSiteId" + ], + "referencedColumns": [ + "localSiteId" + ] + } + ] + }, + { + "tableName": "VisitorSummaryStatsEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `date` TEXT NOT NULL, `granularity` TEXT NOT NULL, `views` INTEGER NOT NULL, `visitors` INTEGER NOT NULL, PRIMARY KEY(`localSiteId`, `date`, `granularity`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "granularity", + "columnName": "granularity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "views", + "columnName": "views", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "visitors", + "columnName": "visitors", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "date", + "granularity" + ] + } + }, + { + "tableName": "ShippingMethod", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `localSiteId` INTEGER NOT NULL, `title` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "id" + ] + } + }, + { + "tableName": "CustomerFromAnalytics", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `userId` INTEGER NOT NULL, `avgOrderValue` REAL NOT NULL, `city` TEXT NOT NULL, `country` TEXT NOT NULL, `dateLastActive` TEXT NOT NULL, `dateLastActiveGmt` TEXT NOT NULL, `dateLastOrder` TEXT NOT NULL, `dateRegistered` TEXT NOT NULL, `dateRegisteredGmt` TEXT NOT NULL, `email` TEXT NOT NULL, `name` TEXT NOT NULL, `ordersCount` INTEGER NOT NULL, `postcode` TEXT NOT NULL, `state` TEXT NOT NULL, `totalSpend` REAL NOT NULL, `username` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `id`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "avgOrderValue", + "columnName": "avgOrderValue", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "city", + "columnName": "city", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "country", + "columnName": "country", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateLastActive", + "columnName": "dateLastActive", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateLastActiveGmt", + "columnName": "dateLastActiveGmt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateLastOrder", + "columnName": "dateLastOrder", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateRegistered", + "columnName": "dateRegistered", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateRegisteredGmt", + "columnName": "dateRegisteredGmt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "ordersCount", + "columnName": "ordersCount", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "postcode", + "columnName": "postcode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "totalSpend", + "columnName": "totalSpend", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "username", + "columnName": "username", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "id" + ] + } + }, + { + "tableName": "ProductEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteId` INTEGER NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, `permalink` TEXT NOT NULL, `dateCreated` TEXT NOT NULL, `dateModified` TEXT NOT NULL, `type` TEXT NOT NULL, `status` TEXT NOT NULL, `featured` INTEGER NOT NULL, `catalogVisibility` TEXT NOT NULL, `description` TEXT NOT NULL, `shortDescription` TEXT NOT NULL, `sku` TEXT NOT NULL, `globalUniqueId` TEXT NOT NULL, `price` TEXT NOT NULL, `regularPrice` TEXT NOT NULL, `salePrice` TEXT NOT NULL, `onSale` INTEGER NOT NULL, `totalSales` INTEGER NOT NULL, `purchasable` INTEGER NOT NULL, `dateOnSaleFrom` TEXT NOT NULL, `dateOnSaleTo` TEXT NOT NULL, `dateOnSaleFromGmt` TEXT NOT NULL, `dateOnSaleToGmt` TEXT NOT NULL, `virtual` INTEGER NOT NULL, `downloadable` INTEGER NOT NULL, `downloadLimit` INTEGER NOT NULL, `downloadExpiry` INTEGER NOT NULL, `soldIndividually` INTEGER NOT NULL, `externalUrl` TEXT NOT NULL, `buttonText` TEXT NOT NULL, `taxStatus` TEXT NOT NULL, `taxClass` TEXT NOT NULL, `manageStock` INTEGER NOT NULL, `stockQuantity` REAL NOT NULL, `stockStatus` TEXT NOT NULL, `backorders` TEXT NOT NULL, `backordersAllowed` INTEGER NOT NULL, `backordered` INTEGER NOT NULL, `shippingRequired` INTEGER NOT NULL, `shippingTaxable` INTEGER NOT NULL, `shippingClass` TEXT NOT NULL, `shippingClassId` INTEGER NOT NULL, `reviewsAllowed` INTEGER NOT NULL, `averageRating` TEXT NOT NULL, `ratingCount` INTEGER NOT NULL, `parentId` INTEGER NOT NULL, `purchaseNote` TEXT NOT NULL, `menuOrder` INTEGER NOT NULL, `categories` TEXT NOT NULL, `tags` TEXT NOT NULL, `images` TEXT NOT NULL, `attributes` TEXT NOT NULL, `variations` TEXT NOT NULL, `downloads` TEXT NOT NULL, `relatedIds` TEXT NOT NULL, `crossSellIds` TEXT NOT NULL, `upsellIds` TEXT NOT NULL, `groupedProductIds` TEXT NOT NULL, `weight` TEXT NOT NULL, `length` TEXT NOT NULL, `width` TEXT NOT NULL, `height` TEXT NOT NULL, `bundledItems` TEXT NOT NULL, `compositeComponents` TEXT NOT NULL, `specialStockStatus` TEXT NOT NULL, `bundleMinSize` REAL, `bundleMaxSize` REAL, `minAllowedQuantity` INTEGER NOT NULL, `maxAllowedQuantity` INTEGER NOT NULL, `groupOfQuantity` INTEGER NOT NULL, `combineVariationQuantities` INTEGER NOT NULL, `password` TEXT, `isSampleProduct` INTEGER NOT NULL, PRIMARY KEY(`localSiteId`, `remoteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "slug", + "columnName": "slug", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "permalink", + "columnName": "permalink", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateModified", + "columnName": "dateModified", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "featured", + "columnName": "featured", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "catalogVisibility", + "columnName": "catalogVisibility", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shortDescription", + "columnName": "shortDescription", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sku", + "columnName": "sku", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "globalUniqueId", + "columnName": "globalUniqueId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "regularPrice", + "columnName": "regularPrice", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "salePrice", + "columnName": "salePrice", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "onSale", + "columnName": "onSale", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "totalSales", + "columnName": "totalSales", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "purchasable", + "columnName": "purchasable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateOnSaleFrom", + "columnName": "dateOnSaleFrom", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateOnSaleTo", + "columnName": "dateOnSaleTo", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateOnSaleFromGmt", + "columnName": "dateOnSaleFromGmt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateOnSaleToGmt", + "columnName": "dateOnSaleToGmt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "virtual", + "columnName": "virtual", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "downloadable", + "columnName": "downloadable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "downloadLimit", + "columnName": "downloadLimit", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "downloadExpiry", + "columnName": "downloadExpiry", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "soldIndividually", + "columnName": "soldIndividually", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "externalUrl", + "columnName": "externalUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "buttonText", + "columnName": "buttonText", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "taxStatus", + "columnName": "taxStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "taxClass", + "columnName": "taxClass", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "manageStock", + "columnName": "manageStock", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "stockQuantity", + "columnName": "stockQuantity", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "stockStatus", + "columnName": "stockStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "backorders", + "columnName": "backorders", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "backordersAllowed", + "columnName": "backordersAllowed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "backordered", + "columnName": "backordered", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shippingRequired", + "columnName": "shippingRequired", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shippingTaxable", + "columnName": "shippingTaxable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shippingClass", + "columnName": "shippingClass", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingClassId", + "columnName": "shippingClassId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "reviewsAllowed", + "columnName": "reviewsAllowed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "averageRating", + "columnName": "averageRating", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "ratingCount", + "columnName": "ratingCount", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "parentId", + "columnName": "parentId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "purchaseNote", + "columnName": "purchaseNote", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "menuOrder", + "columnName": "menuOrder", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "categories", + "columnName": "categories", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "tags", + "columnName": "tags", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "images", + "columnName": "images", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "attributes", + "columnName": "attributes", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "variations", + "columnName": "variations", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "downloads", + "columnName": "downloads", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "relatedIds", + "columnName": "relatedIds", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "crossSellIds", + "columnName": "crossSellIds", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "upsellIds", + "columnName": "upsellIds", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "groupedProductIds", + "columnName": "groupedProductIds", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "weight", + "columnName": "weight", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "length", + "columnName": "length", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "width", + "columnName": "width", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "height", + "columnName": "height", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "bundledItems", + "columnName": "bundledItems", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "compositeComponents", + "columnName": "compositeComponents", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "specialStockStatus", + "columnName": "specialStockStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "bundleMinSize", + "columnName": "bundleMinSize", + "affinity": "REAL" + }, + { + "fieldPath": "bundleMaxSize", + "columnName": "bundleMaxSize", + "affinity": "REAL" + }, + { + "fieldPath": "minAllowedQuantity", + "columnName": "minAllowedQuantity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "maxAllowedQuantity", + "columnName": "maxAllowedQuantity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "groupOfQuantity", + "columnName": "groupOfQuantity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "combineVariationQuantities", + "columnName": "combineVariationQuantities", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "password", + "columnName": "password", + "affinity": "TEXT" + }, + { + "fieldPath": "isSampleProduct", + "columnName": "isSampleProduct", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteId" + ] + } + }, + { + "tableName": "PosProductEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteId` INTEGER NOT NULL, `name` TEXT NOT NULL, `sku` TEXT NOT NULL, `globalUniqueId` TEXT NOT NULL, `type` TEXT NOT NULL, `price` TEXT NOT NULL, `downloadable` INTEGER NOT NULL, `images` TEXT NOT NULL, `attributes` TEXT NOT NULL, `parentId` INTEGER, `status` TEXT NOT NULL, `regularPrice` TEXT NOT NULL, `salePrice` TEXT NOT NULL, `onSale` INTEGER NOT NULL, `description` TEXT NOT NULL, `shortDescription` TEXT NOT NULL, `manageStock` INTEGER NOT NULL, `stockQuantity` REAL, `stockStatus` TEXT NOT NULL, `backordersAllowed` INTEGER NOT NULL, `backordered` INTEGER NOT NULL, `categories` TEXT NOT NULL, `tags` TEXT NOT NULL, `dateModified` TEXT NOT NULL, `variations` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `remoteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sku", + "columnName": "sku", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "globalUniqueId", + "columnName": "globalUniqueId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "downloadable", + "columnName": "downloadable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "images", + "columnName": "images", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "attributes", + "columnName": "attributes", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "parentId", + "columnName": "parentId", + "affinity": "INTEGER" + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "regularPrice", + "columnName": "regularPrice", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "salePrice", + "columnName": "salePrice", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "onSale", + "columnName": "onSale", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shortDescription", + "columnName": "shortDescription", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "manageStock", + "columnName": "manageStock", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "stockQuantity", + "columnName": "stockQuantity", + "affinity": "REAL" + }, + { + "fieldPath": "stockStatus", + "columnName": "stockStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "backordersAllowed", + "columnName": "backordersAllowed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "backordered", + "columnName": "backordered", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "categories", + "columnName": "categories", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "tags", + "columnName": "tags", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateModified", + "columnName": "dateModified", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "variations", + "columnName": "variations", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteId" + ] + } + }, + { + "tableName": "PosVariationEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteProductId` INTEGER NOT NULL, `remoteVariationId` INTEGER NOT NULL, `dateModified` TEXT NOT NULL, `sku` TEXT NOT NULL, `globalUniqueId` TEXT NOT NULL, `variationName` TEXT NOT NULL, `price` TEXT NOT NULL, `regularPrice` TEXT NOT NULL, `salePrice` TEXT NOT NULL, `description` TEXT NOT NULL, `stockQuantity` REAL NOT NULL, `stockStatus` TEXT NOT NULL, `manageStock` INTEGER NOT NULL, `backordered` INTEGER NOT NULL, `attributesJson` TEXT NOT NULL, `imageUrl` TEXT NOT NULL, `status` TEXT NOT NULL, `lastUpdated` TEXT NOT NULL, `downloadable` INTEGER NOT NULL, PRIMARY KEY(`localSiteId`, `remoteProductId`, `remoteVariationId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteProductId", + "columnName": "remoteProductId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteVariationId", + "columnName": "remoteVariationId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateModified", + "columnName": "dateModified", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sku", + "columnName": "sku", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "globalUniqueId", + "columnName": "globalUniqueId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "variationName", + "columnName": "variationName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "regularPrice", + "columnName": "regularPrice", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "salePrice", + "columnName": "salePrice", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "stockQuantity", + "columnName": "stockQuantity", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "stockStatus", + "columnName": "stockStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "manageStock", + "columnName": "manageStock", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "backordered", + "columnName": "backordered", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "attributesJson", + "columnName": "attributesJson", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "imageUrl", + "columnName": "imageUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lastUpdated", + "columnName": "lastUpdated", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "downloadable", + "columnName": "downloadable", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteProductId", + "remoteVariationId" + ] + } + }, + { + "tableName": "ProductCategoryEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteCategoryId` INTEGER NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, `parent` INTEGER NOT NULL, PRIMARY KEY(`localSiteId`, `remoteCategoryId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteCategoryId", + "columnName": "remoteCategoryId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "slug", + "columnName": "slug", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "parent", + "columnName": "parent", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteCategoryId" + ] + } + }, + { + "tableName": "ProductVariationEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteProductId` INTEGER NOT NULL, `remoteVariationId` INTEGER NOT NULL, `dateCreated` TEXT NOT NULL, `dateModified` TEXT NOT NULL, `description` TEXT NOT NULL, `permalink` TEXT NOT NULL, `sku` TEXT NOT NULL, `globalUniqueId` TEXT NOT NULL, `status` TEXT NOT NULL, `price` TEXT NOT NULL, `regularPrice` TEXT NOT NULL, `salePrice` TEXT NOT NULL, `dateOnSaleFrom` TEXT NOT NULL, `dateOnSaleTo` TEXT NOT NULL, `dateOnSaleFromGmt` TEXT NOT NULL, `dateOnSaleToGmt` TEXT NOT NULL, `taxStatus` TEXT NOT NULL, `taxClass` TEXT NOT NULL, `onSale` INTEGER NOT NULL, `purchasable` INTEGER NOT NULL, `virtual` INTEGER NOT NULL, `downloadable` INTEGER NOT NULL, `downloadLimit` INTEGER NOT NULL, `downloadExpiry` INTEGER NOT NULL, `downloads` TEXT NOT NULL, `backorders` TEXT NOT NULL, `backordersAllowed` INTEGER NOT NULL, `backordered` INTEGER NOT NULL, `shippingClass` TEXT NOT NULL, `shippingClassId` INTEGER NOT NULL, `manageStock` INTEGER NOT NULL, `stockQuantity` REAL NOT NULL, `stockStatus` TEXT NOT NULL, `image` TEXT NOT NULL, `weight` TEXT NOT NULL, `length` TEXT NOT NULL, `width` TEXT NOT NULL, `height` TEXT NOT NULL, `minAllowedQuantity` INTEGER NOT NULL, `maxAllowedQuantity` INTEGER NOT NULL, `groupOfQuantity` INTEGER NOT NULL, `overrideProductQuantities` INTEGER NOT NULL, `menuOrder` INTEGER NOT NULL, `attributes` TEXT NOT NULL, `metadata` TEXT, PRIMARY KEY(`localSiteId`, `remoteProductId`, `remoteVariationId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteProductId", + "columnName": "remoteProductId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteVariationId", + "columnName": "remoteVariationId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateModified", + "columnName": "dateModified", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "permalink", + "columnName": "permalink", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sku", + "columnName": "sku", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "globalUniqueId", + "columnName": "globalUniqueId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "regularPrice", + "columnName": "regularPrice", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "salePrice", + "columnName": "salePrice", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateOnSaleFrom", + "columnName": "dateOnSaleFrom", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateOnSaleTo", + "columnName": "dateOnSaleTo", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateOnSaleFromGmt", + "columnName": "dateOnSaleFromGmt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateOnSaleToGmt", + "columnName": "dateOnSaleToGmt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "taxStatus", + "columnName": "taxStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "taxClass", + "columnName": "taxClass", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "onSale", + "columnName": "onSale", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "purchasable", + "columnName": "purchasable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "virtual", + "columnName": "virtual", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "downloadable", + "columnName": "downloadable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "downloadLimit", + "columnName": "downloadLimit", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "downloadExpiry", + "columnName": "downloadExpiry", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "downloads", + "columnName": "downloads", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "backorders", + "columnName": "backorders", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "backordersAllowed", + "columnName": "backordersAllowed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "backordered", + "columnName": "backordered", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shippingClass", + "columnName": "shippingClass", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingClassId", + "columnName": "shippingClassId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "manageStock", + "columnName": "manageStock", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "stockQuantity", + "columnName": "stockQuantity", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "stockStatus", + "columnName": "stockStatus", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "image", + "columnName": "image", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "weight", + "columnName": "weight", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "length", + "columnName": "length", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "width", + "columnName": "width", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "height", + "columnName": "height", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "minAllowedQuantity", + "columnName": "minAllowedQuantity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "maxAllowedQuantity", + "columnName": "maxAllowedQuantity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "groupOfQuantity", + "columnName": "groupOfQuantity", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "overrideProductQuantities", + "columnName": "overrideProductQuantities", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "menuOrder", + "columnName": "menuOrder", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "attributes", + "columnName": "attributes", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "metadata", + "columnName": "metadata", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteProductId", + "remoteVariationId" + ] + } + }, + { + "tableName": "ProductTagEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteTagId` INTEGER NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, `description` TEXT NOT NULL, `count` INTEGER NOT NULL, PRIMARY KEY(`localSiteId`, `remoteTagId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteTagId", + "columnName": "remoteTagId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "slug", + "columnName": "slug", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "count", + "columnName": "count", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteTagId" + ] + } + }, + { + "tableName": "ProductShippingClassEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteShippingClassId` INTEGER NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, `description` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `remoteShippingClassId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteShippingClassId", + "columnName": "remoteShippingClassId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "slug", + "columnName": "slug", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteShippingClassId" + ] + } + }, + { + "tableName": "ProductReviewEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteProductReviewId` INTEGER NOT NULL, `remoteProductId` INTEGER NOT NULL, `dateCreated` TEXT NOT NULL, `status` TEXT NOT NULL, `reviewerName` TEXT NOT NULL, `reviewerEmail` TEXT NOT NULL, `review` TEXT NOT NULL, `rating` INTEGER NOT NULL, `verified` INTEGER NOT NULL, `reviewerAvatarsJson` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `remoteProductReviewId`, `remoteProductId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteProductReviewId", + "columnName": "remoteProductReviewId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteProductId", + "columnName": "remoteProductId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "reviewerName", + "columnName": "reviewerName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "reviewerEmail", + "columnName": "reviewerEmail", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "review", + "columnName": "review", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "rating", + "columnName": "rating", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "verified", + "columnName": "verified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "reviewerAvatarsJson", + "columnName": "reviewerAvatarsJson", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteProductReviewId", + "remoteProductId" + ] + } + }, + { + "tableName": "ProductSettingsEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `weightUnit` TEXT NOT NULL, `dimensionUnit` TEXT NOT NULL, PRIMARY KEY(`localSiteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "weightUnit", + "columnName": "weightUnit", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dimensionUnit", + "columnName": "dimensionUnit", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId" + ] + } + }, + { + "tableName": "CustomerEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `localSiteId` INTEGER NOT NULL, `remoteCustomerId` INTEGER NOT NULL, `avatarUrl` TEXT NOT NULL, `dateCreated` TEXT NOT NULL, `dateCreatedGmt` TEXT NOT NULL, `dateModified` TEXT NOT NULL, `dateModifiedGmt` TEXT NOT NULL, `email` TEXT NOT NULL, `firstName` TEXT NOT NULL, `isPayingCustomer` INTEGER NOT NULL, `lastName` TEXT NOT NULL, `role` TEXT NOT NULL, `username` TEXT NOT NULL, `billingAddress1` TEXT NOT NULL, `billingAddress2` TEXT NOT NULL, `billingCity` TEXT NOT NULL, `billingCompany` TEXT NOT NULL, `billingCountry` TEXT NOT NULL, `billingEmail` TEXT NOT NULL, `billingFirstName` TEXT NOT NULL, `billingLastName` TEXT NOT NULL, `billingPhone` TEXT NOT NULL, `billingPostcode` TEXT NOT NULL, `billingState` TEXT NOT NULL, `shippingAddress1` TEXT NOT NULL, `shippingAddress2` TEXT NOT NULL, `shippingCity` TEXT NOT NULL, `shippingCompany` TEXT NOT NULL, `shippingCountry` TEXT NOT NULL, `shippingFirstName` TEXT NOT NULL, `shippingLastName` TEXT NOT NULL, `shippingPostcode` TEXT NOT NULL, `shippingState` TEXT NOT NULL, `analyticsCustomerId` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteCustomerId", + "columnName": "remoteCustomerId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "avatarUrl", + "columnName": "avatarUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateCreatedGmt", + "columnName": "dateCreatedGmt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateModified", + "columnName": "dateModified", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateModifiedGmt", + "columnName": "dateModifiedGmt", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "firstName", + "columnName": "firstName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isPayingCustomer", + "columnName": "isPayingCustomer", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastName", + "columnName": "lastName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "role", + "columnName": "role", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "username", + "columnName": "username", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingAddress1", + "columnName": "billingAddress1", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingAddress2", + "columnName": "billingAddress2", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingCity", + "columnName": "billingCity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingCompany", + "columnName": "billingCompany", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingCountry", + "columnName": "billingCountry", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingEmail", + "columnName": "billingEmail", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingFirstName", + "columnName": "billingFirstName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingLastName", + "columnName": "billingLastName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingPhone", + "columnName": "billingPhone", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingPostcode", + "columnName": "billingPostcode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "billingState", + "columnName": "billingState", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingAddress1", + "columnName": "shippingAddress1", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingAddress2", + "columnName": "shippingAddress2", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingCity", + "columnName": "shippingCity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingCompany", + "columnName": "shippingCompany", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingCountry", + "columnName": "shippingCountry", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingFirstName", + "columnName": "shippingFirstName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingLastName", + "columnName": "shippingLastName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingPostcode", + "columnName": "shippingPostcode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shippingState", + "columnName": "shippingState", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "analyticsCustomerId", + "columnName": "analyticsCustomerId", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "LocationEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`parentCode` TEXT NOT NULL, `code` TEXT NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`parentCode`, `code`))", + "fields": [ + { + "fieldPath": "parentCode", + "columnName": "parentCode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "code", + "columnName": "code", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "parentCode", + "code" + ] + } + }, + { + "tableName": "OrderShipmentProviderEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `country` TEXT NOT NULL, `carrierName` TEXT NOT NULL, `carrierLink` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `carrierName`, `country`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "country", + "columnName": "country", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "carrierName", + "columnName": "carrierName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "carrierLink", + "columnName": "carrierLink", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "carrierName", + "country" + ] + } + }, + { + "tableName": "UserEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `remoteUserId` INTEGER NOT NULL, `firstName` TEXT NOT NULL, `lastName` TEXT NOT NULL, `username` TEXT NOT NULL, `email` TEXT NOT NULL, `roles` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `remoteUserId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteUserId", + "columnName": "remoteUserId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "firstName", + "columnName": "firstName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lastName", + "columnName": "lastName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "username", + "columnName": "username", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roles", + "columnName": "roles", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "remoteUserId" + ] + } + }, + { + "tableName": "TaxClassEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `slug`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "slug", + "columnName": "slug", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "slug" + ] + } + }, + { + "tableName": "SettingsEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `currencyCode` TEXT NOT NULL, `currencyPosition` TEXT NOT NULL, `currencyThousandSeparator` TEXT NOT NULL, `currencyDecimalSeparator` TEXT NOT NULL, `currencyDecimalNumber` INTEGER NOT NULL, `countryCode` TEXT NOT NULL, `stateCode` TEXT NOT NULL, `address` TEXT NOT NULL, `address2` TEXT NOT NULL, `city` TEXT NOT NULL, `postalCode` TEXT NOT NULL, `couponsEnabled` INTEGER NOT NULL, PRIMARY KEY(`localSiteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "currencyCode", + "columnName": "currencyCode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currencyPosition", + "columnName": "currencyPosition", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currencyThousandSeparator", + "columnName": "currencyThousandSeparator", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currencyDecimalSeparator", + "columnName": "currencyDecimalSeparator", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currencyDecimalNumber", + "columnName": "currencyDecimalNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "countryCode", + "columnName": "countryCode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "stateCode", + "columnName": "stateCode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "address2", + "columnName": "address2", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "city", + "columnName": "city", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "postalCode", + "columnName": "postalCode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "couponsEnabled", + "columnName": "couponsEnabled", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId" + ] + } + }, + { + "tableName": "OrderSummaryEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`siteId` INTEGER NOT NULL, `orderId` INTEGER NOT NULL, `dateCreated` TEXT NOT NULL, PRIMARY KEY(`siteId`, `orderId`))", + "fields": [ + { + "fieldPath": "siteId", + "columnName": "siteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "orderId", + "columnName": "orderId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "siteId", + "orderId" + ] + } + }, + { + "tableName": "OrderStatusEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`siteId` INTEGER NOT NULL, `statusKey` TEXT NOT NULL, `label` TEXT NOT NULL, `statusCount` INTEGER NOT NULL, `position` INTEGER NOT NULL, PRIMARY KEY(`siteId`, `statusKey`))", + "fields": [ + { + "fieldPath": "siteId", + "columnName": "siteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "statusKey", + "columnName": "statusKey", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "label", + "columnName": "label", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "statusCount", + "columnName": "statusCount", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "position", + "columnName": "position", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "siteId", + "statusKey" + ] + } + }, + { + "tableName": "WooShippingLabelEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `orderId` INTEGER NOT NULL, `labelId` INTEGER NOT NULL, `tracking` TEXT NOT NULL, `refundableAmount` TEXT NOT NULL, `status` TEXT NOT NULL, `created` TEXT, `carrierId` TEXT NOT NULL, `serviceName` TEXT NOT NULL, `commercialInvoiceUrl` TEXT, `isCommercialInvoiceSubmittedElectronically` INTEGER NOT NULL, `packageName` TEXT NOT NULL, `isLetter` INTEGER NOT NULL, `productNames` TEXT NOT NULL, `productIds` TEXT, `shipmentId` TEXT, `receiptItemId` INTEGER NOT NULL, `createdDate` TEXT, `mainReceiptId` INTEGER NOT NULL, `rate` TEXT NOT NULL, `currency` TEXT NOT NULL, `expiryDate` INTEGER NOT NULL, `usedDate` INTEGER, `refund` TEXT, `hazmatCategory` TEXT, `originAddress` TEXT, `destinationAddress` TEXT, PRIMARY KEY(`localSiteId`, `orderId`, `labelId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "orderId", + "columnName": "orderId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "labelId", + "columnName": "labelId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "tracking", + "columnName": "tracking", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "refundableAmount", + "columnName": "refundableAmount", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "created", + "columnName": "created", + "affinity": "TEXT" + }, + { + "fieldPath": "carrierId", + "columnName": "carrierId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "serviceName", + "columnName": "serviceName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "commercialInvoiceUrl", + "columnName": "commercialInvoiceUrl", + "affinity": "TEXT" + }, + { + "fieldPath": "isCommercialInvoiceSubmittedElectronically", + "columnName": "isCommercialInvoiceSubmittedElectronically", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "packageName", + "columnName": "packageName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isLetter", + "columnName": "isLetter", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "productNames", + "columnName": "productNames", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "productIds", + "columnName": "productIds", + "affinity": "TEXT" + }, + { + "fieldPath": "shipmentId", + "columnName": "shipmentId", + "affinity": "TEXT" + }, + { + "fieldPath": "receiptItemId", + "columnName": "receiptItemId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "createdDate", + "columnName": "createdDate", + "affinity": "TEXT" + }, + { + "fieldPath": "mainReceiptId", + "columnName": "mainReceiptId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "rate", + "columnName": "rate", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "expiryDate", + "columnName": "expiryDate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "usedDate", + "columnName": "usedDate", + "affinity": "INTEGER" + }, + { + "fieldPath": "refund", + "columnName": "refund", + "affinity": "TEXT" + }, + { + "fieldPath": "hazmatCategory", + "columnName": "hazmatCategory", + "affinity": "TEXT" + }, + { + "fieldPath": "originAddress", + "columnName": "originAddress", + "affinity": "TEXT" + }, + { + "fieldPath": "destinationAddress", + "columnName": "destinationAddress", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "orderId", + "labelId" + ] + } + }, + { + "tableName": "WooShippingShipmentEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `orderId` INTEGER NOT NULL, `shipmentId` TEXT NOT NULL, `items` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `orderId`, `shipmentId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "orderId", + "columnName": "orderId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shipmentId", + "columnName": "shipmentId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "items", + "columnName": "items", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "orderId", + "shipmentId" + ] + } + }, + { + "tableName": "WooShippingPackagesEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `storeOptions` TEXT NOT NULL, `savedPackages` TEXT NOT NULL, `carrierPackageGroups` TEXT NOT NULL, PRIMARY KEY(`localSiteId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "storeOptions", + "columnName": "storeOptions", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "savedPackages", + "columnName": "savedPackages", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "carrierPackageGroups", + "columnName": "carrierPackageGroups", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId" + ] + } + }, + { + "tableName": "GlobalAttributeEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`siteId` INTEGER NOT NULL, `remoteId` INTEGER NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, `type` TEXT NOT NULL, `orderBy` TEXT NOT NULL, `hasArchives` INTEGER NOT NULL, PRIMARY KEY(`siteId`, `remoteId`))", + "fields": [ + { + "fieldPath": "siteId", + "columnName": "siteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "remoteId", + "columnName": "remoteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "slug", + "columnName": "slug", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "orderBy", + "columnName": "orderBy", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "hasArchives", + "columnName": "hasArchives", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "siteId", + "remoteId" + ] + } + }, + { + "tableName": "GatewayEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`siteId` INTEGER NOT NULL, `gatewayId` TEXT NOT NULL, `data` TEXT NOT NULL, PRIMARY KEY(`siteId`, `gatewayId`))", + "fields": [ + { + "fieldPath": "siteId", + "columnName": "siteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "gatewayId", + "columnName": "gatewayId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "data", + "columnName": "data", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "siteId", + "gatewayId" + ] + } + }, + { + "tableName": "NewVisitorStatsEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `granularity` TEXT NOT NULL, `date` TEXT NOT NULL, `startDate` TEXT NOT NULL, `endDate` TEXT NOT NULL, `quantity` TEXT NOT NULL, `fields` TEXT NOT NULL, `data` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `granularity`, `date`, `quantity`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "granularity", + "columnName": "granularity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "startDate", + "columnName": "startDate", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "endDate", + "columnName": "endDate", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "quantity", + "columnName": "quantity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "fields", + "columnName": "fields", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "data", + "columnName": "data", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "granularity", + "date", + "quantity" + ] + } + }, + { + "tableName": "Bookings", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `localSiteId` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `allDay` INTEGER NOT NULL, `status` TEXT NOT NULL, `cost` TEXT NOT NULL, `currency` TEXT NOT NULL, `customerId` INTEGER NOT NULL, `productId` INTEGER NOT NULL, `resourceId` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `dateModified` INTEGER NOT NULL, `googleCalendarEventId` TEXT NOT NULL, `orderId` INTEGER NOT NULL, `orderItemId` INTEGER NOT NULL, `parentId` INTEGER NOT NULL, `personCounts` TEXT, `localTimezone` TEXT NOT NULL, `order_status` TEXT, `order_product_name` TEXT, `order_customer_billingFirstName` TEXT, `order_customer_billingLastName` TEXT, `order_customer_billingCompany` TEXT, `order_customer_billingAddress1` TEXT, `order_customer_billingAddress2` TEXT, `order_customer_billingCity` TEXT, `order_customer_billingState` TEXT, `order_customer_billingPostcode` TEXT, `order_customer_billingCountry` TEXT, `order_customer_billingEmail` TEXT, `order_customer_billingPhone` TEXT, `order_payment_subtotal` TEXT, `order_payment_subtotalTax` TEXT, `order_payment_total` TEXT, `order_payment_totalTax` TEXT, PRIMARY KEY(`id`, `localSiteId`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "start", + "columnName": "start", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "end", + "columnName": "end", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "allDay", + "columnName": "allDay", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "cost", + "columnName": "cost", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "customerId", + "columnName": "customerId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "productId", + "columnName": "productId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "resourceId", + "columnName": "resourceId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateCreated", + "columnName": "dateCreated", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateModified", + "columnName": "dateModified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "googleCalendarEventId", + "columnName": "googleCalendarEventId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "orderId", + "columnName": "orderId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "orderItemId", + "columnName": "orderItemId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "parentId", + "columnName": "parentId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "personCounts", + "columnName": "personCounts", + "affinity": "TEXT" + }, + { + "fieldPath": "localTimezone", + "columnName": "localTimezone", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "order.status", + "columnName": "order_status", + "affinity": "TEXT" + }, + { + "fieldPath": "order.productInfo.name", + "columnName": "order_product_name", + "affinity": "TEXT" + }, + { + "fieldPath": "order.customerInfo.billingFirstName", + "columnName": "order_customer_billingFirstName", + "affinity": "TEXT" + }, + { + "fieldPath": "order.customerInfo.billingLastName", + "columnName": "order_customer_billingLastName", + "affinity": "TEXT" + }, + { + "fieldPath": "order.customerInfo.billingCompany", + "columnName": "order_customer_billingCompany", + "affinity": "TEXT" + }, + { + "fieldPath": "order.customerInfo.billingAddress1", + "columnName": "order_customer_billingAddress1", + "affinity": "TEXT" + }, + { + "fieldPath": "order.customerInfo.billingAddress2", + "columnName": "order_customer_billingAddress2", + "affinity": "TEXT" + }, + { + "fieldPath": "order.customerInfo.billingCity", + "columnName": "order_customer_billingCity", + "affinity": "TEXT" + }, + { + "fieldPath": "order.customerInfo.billingState", + "columnName": "order_customer_billingState", + "affinity": "TEXT" + }, + { + "fieldPath": "order.customerInfo.billingPostcode", + "columnName": "order_customer_billingPostcode", + "affinity": "TEXT" + }, + { + "fieldPath": "order.customerInfo.billingCountry", + "columnName": "order_customer_billingCountry", + "affinity": "TEXT" + }, + { + "fieldPath": "order.customerInfo.billingEmail", + "columnName": "order_customer_billingEmail", + "affinity": "TEXT" + }, + { + "fieldPath": "order.customerInfo.billingPhone", + "columnName": "order_customer_billingPhone", + "affinity": "TEXT" + }, + { + "fieldPath": "order.paymentInfo.subtotal", + "columnName": "order_payment_subtotal", + "affinity": "TEXT" + }, + { + "fieldPath": "order.paymentInfo.subtotalTax", + "columnName": "order_payment_subtotalTax", + "affinity": "TEXT" + }, + { + "fieldPath": "order.paymentInfo.total", + "columnName": "order_payment_total", + "affinity": "TEXT" + }, + { + "fieldPath": "order.paymentInfo.totalTax", + "columnName": "order_payment_totalTax", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id", + "localSiteId" + ] + } + }, + { + "tableName": "RevenueStatsEntity", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `interval` TEXT NOT NULL, `startDate` TEXT NOT NULL, `endDate` TEXT NOT NULL, `data` TEXT NOT NULL, `total` TEXT NOT NULL, `rangeId` TEXT NOT NULL, PRIMARY KEY(`localSiteId`, `rangeId`))", + "fields": [ + { + "fieldPath": "localSiteId", + "columnName": "localSiteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "interval", + "columnName": "interval", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "startDate", + "columnName": "startDate", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "endDate", + "columnName": "endDate", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "data", + "columnName": "data", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "total", + "columnName": "total", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "rangeId", + "columnName": "rangeId", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "localSiteId", + "rangeId" + ] + } + } + ], + "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, 'd5062b5e8fcdf91affe375df7ef6d4fd')" + ] + } +} \ No newline at end of file diff --git a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/bookings/BookingDtoMapper.kt b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/bookings/BookingDtoMapper.kt new file mode 100644 index 000000000000..bf69c326d340 --- /dev/null +++ b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/bookings/BookingDtoMapper.kt @@ -0,0 +1,94 @@ +package org.wordpress.android.fluxc.network.rest.wpcom.wc.bookings + +import org.wordpress.android.fluxc.model.LocalOrRemoteId.LocalId +import org.wordpress.android.fluxc.model.LocalOrRemoteId.RemoteId +import org.wordpress.android.fluxc.persistence.dao.ProductsDao +import org.wordpress.android.fluxc.persistence.entity.BookingEntity +import org.wordpress.android.fluxc.persistence.entity.OrderEntity +import java.math.BigDecimal +import java.time.Instant +import javax.inject.Inject + +internal class BookingDtoMapper @Inject constructor( + private val productsDao: ProductsDao +) { + private val OrderEntity.hasBillingInfo + get() = billingFirstName.isNotEmpty() || + billingLastName.isNotEmpty() || + billingCompany.isNotEmpty() || + billingAddress1.isNotEmpty() || + billingAddress2.isNotEmpty() || + billingCity.isNotEmpty() || + billingState.isNotEmpty() || + billingPostcode.isNotEmpty() || + billingCountry.isNotEmpty() || + billingEmail.isNotEmpty() || + billingPhone.isNotEmpty() + + suspend fun BookingDto.toEntity( + localSiteId: LocalId, + orderEntity: OrderEntity? + ): BookingEntity = BookingEntity( + id = RemoteId(id), + localSiteId = localSiteId, + start = Instant.ofEpochSecond(start), + end = Instant.ofEpochSecond(end), + allDay = allDay, + status = BookingEntity.Status.fromKey(status), + cost = cost, + currency = currency, + customerId = customerId, + productId = productId, + resourceId = resourceId, + dateCreated = Instant.ofEpochSecond(dateCreated), + dateModified = Instant.ofEpochSecond(dateModified), + googleCalendarEventId = googleCalendarEventId, + orderId = orderId, + orderItemId = orderItemId, + parentId = parentId, + personCounts = personCounts?.map { it.toLong() }, + localTimezone = localTimezone, + order = orderEntity?.toBookingOrderInfo(orderItemId) ?: BookingOrderInfo( + productInfo = productsDao.getProduct(localSiteId.value, productId)?.let { + BookingProductInfo(name = it.name) + } + ) + ) + + private suspend fun OrderEntity.toBookingOrderInfo( + orderItemId: Long + ): BookingOrderInfo { + val lineItem = getLineItemList().firstOrNull { it.id == orderItemId } + return BookingOrderInfo( + status = status, + productInfo = BookingProductInfo( + name = lineItem?.name.orEmpty() + ), + customerInfo = if (hasBillingInfo) { + BookingCustomerInfo( + billingFirstName = billingFirstName.ifEmpty { null }, + billingLastName = billingLastName.ifEmpty { null }, + billingCompany = billingCompany.ifEmpty { null }, + billingAddress1 = billingAddress1.ifEmpty { null }, + billingAddress2 = billingAddress2.ifEmpty { null }, + billingCity = billingCity.ifEmpty { null }, + billingState = billingState.ifEmpty { null }, + billingPostcode = billingPostcode.ifEmpty { null }, + billingCountry = billingCountry.ifEmpty { null }, + billingEmail = billingEmail.ifEmpty { null }, + billingPhone = billingPhone.ifEmpty { null }, + ) + } else { + null + }, + paymentInfo = lineItem?.let { + BookingPaymentInfo( + subtotal = it.subtotal?.toBigDecimalOrNull() ?: BigDecimal.ZERO, + subtotalTax = it.subtotalTax?.toBigDecimalOrNull() ?: BigDecimal.ZERO, + total = it.total?.toBigDecimalOrNull() ?: BigDecimal.ZERO, + totalTax = it.totalTax?.toBigDecimalOrNull() ?: BigDecimal.ZERO, + ) + } + ) + } +} diff --git a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/bookings/BookingOrderInfo.kt b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/bookings/BookingOrderInfo.kt new file mode 100644 index 000000000000..97b395079820 --- /dev/null +++ b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/bookings/BookingOrderInfo.kt @@ -0,0 +1,37 @@ +package org.wordpress.android.fluxc.network.rest.wpcom.wc.bookings + +import androidx.room.ColumnInfo +import androidx.room.Embedded +import java.math.BigDecimal + +data class BookingOrderInfo( + val status: String? = null, + @Embedded(prefix = "product_") val productInfo: BookingProductInfo? = null, + @Embedded(prefix = "customer_") val customerInfo: BookingCustomerInfo? = null, + @Embedded(prefix = "payment_") val paymentInfo: BookingPaymentInfo? = null, +) + +data class BookingProductInfo( + @ColumnInfo val name: String, +) + +data class BookingCustomerInfo( + @ColumnInfo val billingFirstName: String? = null, + @ColumnInfo val billingLastName: String? = null, + @ColumnInfo val billingCompany: String? = null, + @ColumnInfo val billingAddress1: String? = null, + @ColumnInfo val billingAddress2: String? = null, + @ColumnInfo val billingCity: String? = null, + @ColumnInfo val billingState: String? = null, + @ColumnInfo val billingPostcode: String? = null, + @ColumnInfo val billingCountry: String? = null, + @ColumnInfo val billingEmail: String? = null, + @ColumnInfo val billingPhone: String? = null, +) + +data class BookingPaymentInfo( + val subtotal: BigDecimal, + val subtotalTax: BigDecimal, + val total: BigDecimal, + val totalTax: BigDecimal, +) diff --git a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/bookings/BookingsStore.kt b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/bookings/BookingsStore.kt index bd13ec93e57c..e77d2d5b051c 100644 --- a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/bookings/BookingsStore.kt +++ b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/bookings/BookingsStore.kt @@ -1,26 +1,28 @@ package org.wordpress.android.fluxc.network.rest.wpcom.wc.bookings 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.SiteModel import org.wordpress.android.fluxc.network.BaseRequest.GenericErrorType.UNKNOWN import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooError import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooErrorType.GENERIC_ERROR import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooResult +import org.wordpress.android.fluxc.network.rest.wpcom.wc.toWooError import org.wordpress.android.fluxc.persistence.dao.BookingsDao import org.wordpress.android.fluxc.persistence.entity.BookingEntity +import org.wordpress.android.fluxc.persistence.entity.OrderEntity +import org.wordpress.android.fluxc.store.WCOrderStore import org.wordpress.android.fluxc.tools.CoroutineEngine import org.wordpress.android.fluxc.utils.HeadersParser import org.wordpress.android.util.AppLog -import java.time.Instant import javax.inject.Inject import javax.inject.Singleton @Singleton -class BookingsStore @Inject constructor( +class BookingsStore @Inject internal constructor( private val bookingsRestClient: BookingsRestClient, + private val orderStore: WCOrderStore, private val bookingsDao: BookingsDao, + private val bookingDtoMapper: BookingDtoMapper, private val headersParser: HeadersParser, private val coroutineEngine: CoroutineEngine, ) { @@ -37,11 +39,25 @@ class BookingsStore @Inject constructor( when { response.isError -> WooResult(response.error) response.result != null -> { + val orderIds = response.result.map { it.orderId }.distinct().filterNot { it == 0L } + val ordersResult = fetchOrders(site, orderIds) + if (ordersResult.isError) { + return@withDefaultContext WooResult(ordersResult.error) + } + if (page == 1 && filters.isEmpty() && query.isNullOrEmpty()) { // Clear existing bookings when fetching the first page bookingsDao.deleteAllForSite(site.localId()) } - val entities = response.result.map { it.toEntity(site.localId()) } + + val entities = response.result.map { + with(bookingDtoMapper) { + it.toEntity( + localSiteId = site.localId(), + orderEntity = ordersResult.model?.get(it.orderId) + ) + } + } bookingsDao.insertOrReplace(entities) val totalPages = headersParser.getTotalPages(response.headers) // Determine if we can load more from the total pages header if available, otherwise @@ -72,25 +88,17 @@ class BookingsStore @Inject constructor( bookingId: Long ): Flow = bookingsDao.observeBooking(site.localId(), bookingId) - private fun BookingDto.toEntity(localSiteId: LocalId): BookingEntity = BookingEntity( - id = RemoteId(id), - localSiteId = localSiteId, - start = Instant.ofEpochSecond(start), - end = Instant.ofEpochSecond(end), - allDay = allDay, - status = BookingEntity.Status.fromKey(status), - cost = cost, - currency = currency, - customerId = customerId, - productId = productId, - resourceId = resourceId, - dateCreated = Instant.ofEpochSecond(dateCreated), - dateModified = Instant.ofEpochSecond(dateModified), - googleCalendarEventId = googleCalendarEventId, - orderId = orderId, - orderItemId = orderItemId, - parentId = parentId, - personCounts = personCounts?.map { it.toLong() }, - localTimezone = localTimezone - ) + private suspend fun fetchOrders( + site: SiteModel, + orderIds: List + ): WooResult> { + if (orderIds.isEmpty()) { return WooResult(emptyMap()) } + + val result = orderStore.fetchOrdersByIds(WCOrderStore.FetchOrdersByIdsPayload(site, orderIds)) + return if (result.isError) { + WooResult(error = result.error?.networkError?.toWooError() ?: WooError(GENERIC_ERROR, UNKNOWN)) + } else { + WooResult(result.fetchedOrders.map { (order, _) -> order }.associateBy { it.orderId }) + } + } } diff --git a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/order/OrderRestClient.kt b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/order/OrderRestClient.kt index 6df4d9145514..cc24dad4e885 100644 --- a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/order/OrderRestClient.kt +++ b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/order/OrderRestClient.kt @@ -339,43 +339,39 @@ class OrderRestClient @Inject constructor( * @param site The WooCommerce [SiteModel] the orders belong to * @param orderIds A list of remote order identifiers to fetch from the API */ - fun fetchOrdersByIds(site: SiteModel, orderIds: List) { - coroutineEngine.launch(T.API, this, "fetchOrdersByIds") { - val url = WOOCOMMERCE.orders.pathV3 - val params = mapOf( - "per_page" to orderIds.size.toString(), - "include" to orderIds.map { it }.joinToString(), - "_fields" to ORDER_FIELDS - ) + suspend fun fetchOrdersByIds(site: SiteModel, orderIds: List): FetchOrdersByIdsResponsePayload { + val url = WOOCOMMERCE.orders.pathV3 + val params = mapOf( + "per_page" to orderIds.size.toString(), + "include" to orderIds.map { it }.joinToString(), + "_fields" to ORDER_FIELDS + ) - val response = wooNetwork.executeGetGsonRequest( - site = site, - path = url, - clazz = Array::class.java, - params = params - ) + val response = wooNetwork.executeGetGsonRequest( + site = site, + path = url, + clazz = Array::class.java, + params = params + ) - when (response) { - is WPAPIResponse.Success -> { - val orderModels = response.data?.map { orderDto -> - orderDtoMapper.toDatabaseEntity(orderDto, site.localId()) - }.orEmpty() + return when (response) { + is WPAPIResponse.Success -> { + val orderModels = response.data?.map { orderDto -> + orderDtoMapper.toDatabaseEntity(orderDto, site.localId()) + }.orEmpty() - val payload = FetchOrdersByIdsResponsePayload( - site = site, - orderIds = orderIds, - fetchedOrders = orderModels - ) - dispatcher.dispatch(WCOrderActionBuilder.newFetchedOrdersByIdsAction(payload)) - } + FetchOrdersByIdsResponsePayload( + site = site, + orderIds = orderIds, + fetchedOrders = orderModels + ) + } - is WPAPIResponse.Error -> { - val orderError = wpAPINetworkErrorToOrderError(response.error) - val payload = FetchOrdersByIdsResponsePayload( - error = orderError, site = site, orderIds = orderIds - ) - dispatcher.dispatch(WCOrderActionBuilder.newFetchedOrdersByIdsAction(payload)) - } + is WPAPIResponse.Error -> { + val orderError = wpAPINetworkErrorToOrderError(response.error) + FetchOrdersByIdsResponsePayload( + error = orderError, site = site, orderIds = orderIds + ) } } } @@ -1230,7 +1226,7 @@ class OrderRestClient @Inject constructor( wpAPINetworkError.type == BaseRequest.GenericErrorType.TIMEOUT -> TIMEOUT_ERROR else -> OrderErrorType.fromString(wpAPINetworkError.errorCode.orEmpty()) } - return OrderError(orderErrorType, wpAPINetworkError.combinedErrorMessage) + return OrderError(orderErrorType, wpAPINetworkError.combinedErrorMessage, wpAPINetworkError) } private fun orderShipmentTrackingResponseToModel( diff --git a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt index d8ac9b58761b..496d4ff84e33 100644 --- a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt +++ b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/WCAndroidDatabase.kt @@ -125,7 +125,7 @@ import org.wordpress.android.fluxc.persistence.migrations.MIGRATION_7_8 import org.wordpress.android.fluxc.persistence.migrations.MIGRATION_8_9 import org.wordpress.android.fluxc.persistence.migrations.MIGRATION_9_10 -const val WC_DATABASE_VERSION = 67 +const val WC_DATABASE_VERSION = 68 @Database( version = WC_DATABASE_VERSION, @@ -225,6 +225,7 @@ const val WC_DATABASE_VERSION = 67 AutoMigration(from = 64, to = 65), AutoMigration(from = 65, to = 66), AutoMigration(from = 66, to = 67), + AutoMigration(from = 67, to = 68) ] ) @TypeConverters( diff --git a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/entity/BookingEntity.kt b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/entity/BookingEntity.kt index 71429e660b97..1349e733066e 100644 --- a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/entity/BookingEntity.kt +++ b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/persistence/entity/BookingEntity.kt @@ -1,10 +1,12 @@ package org.wordpress.android.fluxc.persistence.entity +import androidx.room.Embedded import androidx.room.Entity import androidx.room.TypeConverter import androidx.room.TypeConverters import org.wordpress.android.fluxc.model.LocalOrRemoteId.LocalId import org.wordpress.android.fluxc.model.LocalOrRemoteId.RemoteId +import org.wordpress.android.fluxc.network.rest.wpcom.wc.bookings.BookingOrderInfo import java.time.Instant @Entity( @@ -31,7 +33,8 @@ data class BookingEntity( val orderItemId: Long, val parentId: Long, val personCounts: List?, - val localTimezone: String + val localTimezone: String, + @Embedded("order_") val order: BookingOrderInfo ) { sealed interface Status { val key: String diff --git a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/store/WCOrderStore.kt b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/store/WCOrderStore.kt index 5f31bce5390c..af04de5f2714 100644 --- a/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/store/WCOrderStore.kt +++ b/libs/fluxc-plugin/src/main/kotlin/org/wordpress/android/fluxc/store/WCOrderStore.kt @@ -11,6 +11,7 @@ import org.wordpress.android.fluxc.action.WCOrderAction import org.wordpress.android.fluxc.action.WCOrderAction.FETCH_ORDERS import org.wordpress.android.fluxc.annotations.action.Action import org.wordpress.android.fluxc.generated.ListActionBuilder +import org.wordpress.android.fluxc.generated.WCOrderActionBuilder import org.wordpress.android.fluxc.model.LocalOrRemoteId.LocalId import org.wordpress.android.fluxc.model.LocalOrRemoteId.RemoteId import org.wordpress.android.fluxc.model.SiteModel @@ -22,6 +23,7 @@ import org.wordpress.android.fluxc.model.WCOrderSummaryModel import org.wordpress.android.fluxc.model.metadata.WCMetaData import org.wordpress.android.fluxc.network.BaseRequest.BaseNetworkError import org.wordpress.android.fluxc.network.BaseRequest.GenericErrorType.SERVER_ERROR +import org.wordpress.android.fluxc.network.rest.wpapi.WPAPINetworkError import org.wordpress.android.fluxc.network.rest.wpapi.WPAPINetworkingMode import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooError import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooErrorType.API_ERROR @@ -326,7 +328,11 @@ class WCOrderStore @Inject internal constructor( ) } - data class OrderError(val type: OrderErrorType = GENERIC_ERROR, val message: String = "") : OnChangedError + data class OrderError( + val type: OrderErrorType = GENERIC_ERROR, + val message: String = "", + val networkError: WPAPINetworkError? = null + ) : OnChangedError enum class OrderErrorType { INVALID_PARAM, @@ -534,7 +540,9 @@ class WCOrderStore @Inject internal constructor( // remote actions FETCH_ORDERS -> fetchOrders(action.payload as FetchOrdersPayload) WCOrderAction.FETCH_ORDER_LIST -> fetchOrderList(action.payload as FetchOrderListPayload) - WCOrderAction.FETCH_ORDERS_BY_IDS -> fetchOrdersByIds(action.payload as FetchOrdersByIdsPayload) + WCOrderAction.FETCH_ORDERS_BY_IDS -> coroutineEngine.launch(API, this, "fetchOrdersByIds") { + fetchOrdersByIds(action.payload as FetchOrdersByIdsPayload) + } WCOrderAction.FETCH_ORDERS_COUNT -> fetchOrdersCount(action.payload as FetchOrdersCountPayload) WCOrderAction.UPDATE_ORDER_STATUS -> throw IllegalStateException("Invalid action. Use suspendable updateOrderStatus(..) directly") @@ -576,9 +584,9 @@ class WCOrderStore @Inject internal constructor( ) } - private fun fetchOrdersByIds(payload: FetchOrdersByIdsPayload) { - payload.orderIds.chunked(NUM_ORDERS_PER_FETCH).forEach { idsToFetch -> - wcOrderRestClient.fetchOrdersByIds(payload.site, idsToFetch) + suspend fun fetchOrdersByIds(payload: FetchOrdersByIdsPayload): FetchOrdersByIdsResponsePayload { + return wcOrderRestClient.fetchOrdersByIds(payload.site, payload.orderIds).also { + mDispatcher.dispatch(WCOrderActionBuilder.newFetchedOrdersByIdsAction(it)) } } diff --git a/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/wc/bookings/BookingDtoMapperTest.kt b/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/wc/bookings/BookingDtoMapperTest.kt new file mode 100644 index 000000000000..6d413c3afa1c --- /dev/null +++ b/libs/fluxc-plugin/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/wc/bookings/BookingDtoMapperTest.kt @@ -0,0 +1,330 @@ +package org.wordpress.android.fluxc.network.rest.wpcom.wc.bookings + +import kotlinx.coroutines.test.runTest +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test +import org.mockito.kotlin.any +import org.mockito.kotlin.given +import org.mockito.kotlin.mock +import org.wordpress.android.fluxc.model.LocalOrRemoteId.LocalId +import org.wordpress.android.fluxc.model.LocalOrRemoteId.RemoteId +import org.wordpress.android.fluxc.model.WCProductModel +import org.wordpress.android.fluxc.persistence.dao.ProductsDao +import org.wordpress.android.fluxc.persistence.entity.BookingEntity +import org.wordpress.android.fluxc.persistence.entity.OrderEntity +import java.math.BigDecimal +import java.time.Instant + +class BookingDtoMapperTest { + private val productsDao: ProductsDao = mock() + private val localSiteId = LocalId(123) + private val mapper = BookingDtoMapper(productsDao) + + @Test + fun `given valid booking dto, when mapping to entity, then all fields are correctly mapped`() = runTest { + // Given + val bookingDto = createSampleBookingDto() + + // When + val result = with(mapper) { bookingDto.toEntity(localSiteId, null) } + + // Then + assertThat(result.id).isEqualTo(RemoteId(1L)) + assertThat(result.localSiteId).isEqualTo(localSiteId) + assertThat(result.start).isEqualTo(Instant.ofEpochSecond(1609459200L)) // 2021-01-01 00:00:00 + assertThat(result.end).isEqualTo(Instant.ofEpochSecond(1609462800L)) // 2021-01-01 01:00:00 + assertThat(result.allDay).isEqualTo(false) + assertThat(result.status).isEqualTo(BookingEntity.Status.Confirmed) + assertThat(result.cost).isEqualTo("50.00") + assertThat(result.currency).isEqualTo("USD") + assertThat(result.customerId).isEqualTo(456L) + assertThat(result.productId).isEqualTo(789L) + assertThat(result.resourceId).isEqualTo(101L) + assertThat(result.dateCreated).isEqualTo(Instant.ofEpochSecond(1609455600L)) + assertThat(result.dateModified).isEqualTo(Instant.ofEpochSecond(1609459200L)) + assertThat(result.googleCalendarEventId).isEqualTo("cal-123") + assertThat(result.orderId).isEqualTo(999L) + assertThat(result.orderItemId).isEqualTo(111L) + assertThat(result.parentId).isEqualTo(0L) + assertThat(result.personCounts).containsExactly(2L, 1L) + assertThat(result.localTimezone).isEqualTo("America/New_York") + assertThat(result.order.productInfo).isNull() + } + + @Test + fun `given booking dto with null person counts, when mapping, then person counts is null`() = runTest { + // Given + val bookingDto = createSampleBookingDto(personCounts = null) + + // When + val result = with(mapper) { bookingDto.toEntity(localSiteId, null) } + + // Then + assertThat(result.personCounts).isNull() + } + + @Test + fun `given booking dto with empty person counts, when mapping, then person counts is empty`() = runTest { + // Given + val bookingDto = createSampleBookingDto(personCounts = emptyList()) + + // When + val result = with(mapper) { bookingDto.toEntity(localSiteId, null) } + + // Then + assertThat(result.personCounts).isEmpty() + } + + @Test + fun `given booking dto with unknown status, when mapping, then status is Unknown`() = runTest { + // Given + val bookingDto = createSampleBookingDto(status = "unknown-status") + + // When + val result = with(mapper) { bookingDto.toEntity(localSiteId, null) } + + // Then + assertThat(result.status).isInstanceOf(BookingEntity.Status.Unknown::class.java) + assertThat(result.status.key).isEqualTo("unknown-status") + } + + @Test + fun `given booking dto with all valid statuses, when mapping, then correct status enum is returned`() = runTest { + val statusMappings = mapOf( + "unpaid" to BookingEntity.Status.Unpaid, + "pending-confirmation" to BookingEntity.Status.PendingConfirmation, + "confirmed" to BookingEntity.Status.Confirmed, + "paid" to BookingEntity.Status.Paid, + "cancelled" to BookingEntity.Status.Cancelled, + "complete" to BookingEntity.Status.Complete + ) + + statusMappings.forEach { (statusKey, expectedStatus) -> + // Given + val bookingDto = createSampleBookingDto(status = statusKey) + + // When + val result = with(mapper) { bookingDto.toEntity(localSiteId, null) } + + // Then + assertThat(result.status).isEqualTo(expectedStatus) + } + } + + @Test + fun `given booking dto with order entity, when mapping, then order info is populated from order`() = runTest { + // Given + val bookingDto = createSampleBookingDto() + val orderEntity = createSampleOrderEntity() + + // When + val result = with(mapper) { bookingDto.toEntity(localSiteId, orderEntity) } + + // Then + with(result.order) { + assertThat(status).isEqualTo("processing") + assertThat(productInfo?.name).isEqualTo("Test Product") + assertThat(customerInfo?.billingFirstName).isEqualTo("John") + assertThat(customerInfo?.billingLastName).isEqualTo("Doe") + assertThat(customerInfo?.billingEmail).isEqualTo("john@example.com") + assertThat(customerInfo?.billingCompany).isNull() // empty string becomes null + assertThat(customerInfo?.billingAddress1).isEqualTo("123 Main St") + assertThat(paymentInfo?.subtotal).isEqualTo(BigDecimal("40.00")) + assertThat(paymentInfo?.total).isEqualTo(BigDecimal("50.00")) + } + } + + @Test + fun `given booking dto without order entity and product exists, when mapping, then order info has product name`() = + runTest { + // Given + val bookingDto = createSampleBookingDto() + val productModel = WCProductModel(name = "Test Product from DB") + given(productsDao.getProduct(localSiteId.value, bookingDto.productId)).willReturn(productModel) + + // When + val result = with(mapper) { bookingDto.toEntity(localSiteId, null) } + + // Then + assertThat(result.order.productInfo?.name).isEqualTo("Test Product from DB") + assertThat(result.order.status).isNull() + assertThat(result.order.customerInfo).isNull() + assertThat(result.order.paymentInfo).isNull() + } + + @Test + fun `given booking dto without order entity and no product, when mapping, then order info has null product info`() = + runTest { + // Given + val bookingDto = createSampleBookingDto() + given(productsDao.getProduct(any(), any())).willReturn(null) + + // When + val result = with(mapper) { bookingDto.toEntity(localSiteId, null) } + + // Then + assertThat(result.order.productInfo).isNull() + assertThat(result.order.status).isNull() + assertThat(result.order.customerInfo).isNull() + assertThat(result.order.paymentInfo).isNull() + } + + @Test + fun `given order entity with empty billing fields, when mapping, then empty strings become null`() = runTest { + // Given + val bookingDto = createSampleBookingDto() + val orderEntity = createSampleOrderEntity().copy( + billingCompany = "", + billingAddress2 = "", + billingCity = "", + billingState = "", + billingPostcode = "", + billingCountry = "", + billingPhone = "" + ) + + // When + val result = with(mapper) { bookingDto.toEntity(localSiteId, orderEntity) } + + // Then + with(result.order.customerInfo!!) { + assertThat(billingCompany).isNull() + assertThat(billingAddress2).isNull() + assertThat(billingCity).isNull() + assertThat(billingState).isNull() + assertThat(billingPostcode).isNull() + assertThat(billingCountry).isNull() + assertThat(billingPhone).isNull() + } + } + + @Test + fun `given order entity with no matching line item, when mapping, then payment info is null`() = runTest { + // Given + val bookingDto = createSampleBookingDto(orderItemId = 999L) // non-matching ID + val orderEntity = createSampleOrderEntity() + + // When + val result = with(mapper) { bookingDto.toEntity(localSiteId, orderEntity) } + + // Then + assertThat(result.order.paymentInfo).isNull() + } + + @Test + fun `given order entity with line item having invalid amounts, when mapping, then defaults to zero`() = runTest { + // Given + val bookingDto = createSampleBookingDto() + val orderEntity = createSampleOrderEntity().copy( + lineItems = "[{\"id\":111,\"name\":\"Test Product\",\"subtotal\":\"invalid\",\"total\":\"also-invalid\",\"subtotal_tax\":null,\"total_tax\":\"\"}]" + ) + + // When + val result = with(mapper) { bookingDto.toEntity(localSiteId, orderEntity) } + + // Then + with(result.order.paymentInfo!!) { + assertThat(subtotal).isEqualTo(BigDecimal.ZERO) + assertThat(total).isEqualTo(BigDecimal.ZERO) + assertThat(subtotalTax).isEqualTo(BigDecimal.ZERO) + assertThat(totalTax).isEqualTo(BigDecimal.ZERO) + } + } + + private fun createSampleBookingDto( + id: Long = 1L, + start: Long = 1609459200L, // 2021-01-01 00:00:00 + end: Long = 1609462800L, // 2021-01-01 01:00:00 + allDay: Boolean = false, + status: String = "confirmed", + cost: String = "50.00", + currency: String = "USD", + customerId: Long = 456L, + productId: Long = 789L, + resourceId: Long = 101L, + dateCreated: Long = 1609455600L, + dateModified: Long = 1609459200L, + googleCalendarEventId: String = "cal-123", + orderId: Long = 999L, + orderItemId: Long = 111L, + parentId: Long = 0L, + personCounts: List? = listOf(2, 1), + localTimezone: String = "America/New_York" + ) = BookingDto( + id = id, + start = start, + end = end, + allDay = allDay, + status = status, + cost = cost, + currency = currency, + customerId = customerId, + productId = productId, + resourceId = resourceId, + dateCreated = dateCreated, + dateModified = dateModified, + googleCalendarEventId = googleCalendarEventId, + orderId = orderId, + orderItemId = orderItemId, + parentId = parentId, + personCounts = personCounts, + localTimezone = localTimezone + ) + + private fun createSampleOrderEntity() = OrderEntity( + localSiteId = localSiteId, + orderId = 999L, + number = "1001", + status = "processing", + currency = "USD", + orderKey = "", + dateCreated = "", + dateModified = "", + total = "50.00", + totalTax = "", + shippingTotal = "", + paymentMethod = "", + paymentMethodTitle = "", + datePaid = "", + pricesIncludeTax = false, + customerNote = "", + discountTotal = "", + discountCodes = "", + customerId = 456L, + billingFirstName = "John", + billingLastName = "Doe", + billingCompany = "", + billingAddress1 = "123 Main St", + billingAddress2 = "Apt 1", + billingCity = "New York", + billingState = "NY", + billingPostcode = "10001", + billingCountry = "US", + billingEmail = "john@example.com", + billingPhone = "555-1234", + shippingFirstName = "", + shippingLastName = "", + shippingCompany = "", + shippingAddress1 = "", + shippingAddress2 = "", + shippingCity = "", + shippingState = "", + shippingPostcode = "", + shippingCountry = "", + shippingPhone = "", + lineItems = "[{\"id\":111,\"name\":\"Test Product\",\"subtotal\":\"40.00\",\"subtotal_tax\":\"5.00\",\"total\":\"50.00\",\"total_tax\":\"7.50\"}]", + shippingLines = "[]", + feeLines = "[]", + taxLines = "[]", + couponLines = "[]", + metaData = emptyList(), + paymentUrl = "", + isEditable = true, + needsPayment = null, + needsProcessing = null, + giftCardCode = "", + giftCardAmount = "", + shippingTax = "", + createdVia = "" + ) +}