Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ sealed class PosLocalCatalogSyncResult {

@Singleton
class WooPosLocalCatalogSyncRepository @Inject constructor(
private val posSyncProductsAction: WooPosSyncProductsAction,
private val posSyncVariationsAction: WooPosSyncVariationsAction,
private val posSyncAction: WooPosSyncAction,
private val posCheckCatalogSizeAction: WooPosCheckCatalogSizeAction,
private val syncTimestampManager: WooPosSyncTimestampManager,
private val preferencesRepository: WooPosPreferencesRepository,
Expand Down Expand Up @@ -120,7 +119,7 @@ class WooPosLocalCatalogSyncRepository @Inject constructor(
pageSize: Int,
maxPages: Int
): WooPosSyncProductsResult {
val result = posSyncProductsAction.execute(site, modifiedAfterGmt, pageSize, maxPages)
val result = posSyncAction.syncProducts(site, modifiedAfterGmt, pageSize, maxPages)

if (result is WooPosSyncProductsResult.Success) {
result.serverDate?.let { serverDate ->
Expand All @@ -140,7 +139,7 @@ class WooPosLocalCatalogSyncRepository @Inject constructor(
pageSize: Int,
maxPages: Int
): WooPosSyncVariationsResult {
val result = posSyncVariationsAction.execute(site, modifiedAfterGmt, pageSize, maxPages)
val result = posSyncAction.syncVariations(site, modifiedAfterGmt, pageSize, maxPages)

if (result is WooPosSyncVariationsResult.Success) {
result.serverDate?.let { serverDate ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,41 @@ import kotlinx.coroutines.coroutineScope
import org.wordpress.android.fluxc.model.SiteModel
import org.wordpress.android.fluxc.network.rest.wpcom.wc.product.CoreProductStatus
import org.wordpress.android.fluxc.persistence.entity.pos.WooPosProductEntity
import org.wordpress.android.fluxc.persistence.entity.pos.WooPosVariationEntity
import org.wordpress.android.fluxc.store.pos.localcatalog.WooPosLocalCatalogFetchProductsResult
import org.wordpress.android.fluxc.store.pos.localcatalog.WooPosLocalCatalogStore
import org.wordpress.android.fluxc.store.pos.localcatalog.WooPosVariationsFetchResult
import javax.inject.Inject

class WooPosSyncAction @Inject constructor(
private val productAction: WooPosSyncProductsAction,
private val variationsAction: WooPosSyncVariationsAction
) {
suspend fun syncProducts(
site: SiteModel,
modifiedAfterGmt: String? = null,
pageSize: Int,
maxPages: Int
) = productAction.execute(
site = site,
modifiedAfterGmt = modifiedAfterGmt,
pageSize = pageSize,
maxPages = maxPages
)

suspend fun syncVariations(
site: SiteModel,
modifiedAfterGmt: String? = null,
pageSize: Int,
maxPages: Int
) = variationsAction.execute(
site = site,
modifiedAfterGmt = modifiedAfterGmt,
pageSize = pageSize,
maxPages = maxPages
)
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📓 All the code within this file below this line was copy-pasted from the separate files.

private typealias ServerDate = String

class WooPosSyncProductsAction @Inject constructor(
Expand Down Expand Up @@ -222,3 +253,153 @@ class WooPosSyncProductsAction @Inject constructor(
}
}
}

class WooPosSyncVariationsAction @Inject constructor(
private val posLocalCatalogStore: WooPosLocalCatalogStore,
private val logger: WooPosLogWrapper,
) {
sealed class WooPosSyncVariationsResult {
data class Success(val variationsSynced: Int, val serverDate: String?) : WooPosSyncVariationsResult()

sealed class Failed(val error: String) : WooPosSyncVariationsResult() {
class CatalogTooLarge(val totalPages: Int, val maxPages: Int) :
Failed("Catalog too large: $totalPages pages exceed maximum of $maxPages pages")

class UnexpectedError(error: String) : Failed(error)
}
}

suspend fun execute(
site: SiteModel,
modifiedAfterGmt: String? = null,
pageSize: Int,
maxPages: Int
): WooPosSyncVariationsResult {
return runCatching {
val (variations, serverDate) = fetchAllPages(site, modifiedAfterGmt, pageSize, maxPages)

posLocalCatalogStore.executeInTransaction {
val isFullSync = modifiedAfterGmt == null
if (isFullSync) {
posLocalCatalogStore.deleteAllVariations(
siteId = site.localId()
).getOrThrow()
}

posLocalCatalogStore.upsertVariations(variations).getOrThrow()
}.fold(
onSuccess = {
logger.d("Local Catalog variations transaction committed successfully")
WooPosSyncVariationsResult.Success(variations.size, serverDate)
},
onFailure = { error ->
handleTransactionError(error)
}
)
}.fold(
onSuccess = { result -> result },
onFailure = { error ->
logger.e("Failed to sync variations: ${error.message}")
when (error) {
is CatalogTooLargeException -> error.toSyncResult()
else -> WooPosSyncVariationsResult.Failed.UnexpectedError(
error.message ?: "Failed to sync variations"
)
}
}
)
}

private suspend fun fetchAllPages(
site: SiteModel,
modifiedAfterGmt: String?,
pageSize: Int,
maxPages: Int
): Pair<List<WooPosVariationEntity>, String> {
var currentPage = 1
var pagesSynced = 0
var totalPages = maxPages
var firstPageServerDate: String? = null

val variations = mutableListOf<WooPosVariationEntity>()

while (pagesSynced < totalPages) {
val result = posLocalCatalogStore.fetchRecentlyModifiedVariations(
site = site,
modifiedAfterGmt = modifiedAfterGmt,
page = currentPage,
pageSize = pageSize,
)

result.fold(
onSuccess = { syncResult ->
processPageResult(syncResult, pagesSynced, maxPages)
if (pagesSynced == 0) {
firstPageServerDate = syncResult.serverDate
}
variations.addAll(syncResult.variations)
totalPages = syncResult.totalPages
pagesSynced++

if (!syncResult.hasMore || syncResult.syncedCount == 0) {
logger.d("Local Catalog: No more variations to sync")
} else {
currentPage = syncResult.nextPage
}
},
onFailure = { error ->
logger.e("Local Catalog Variations sync failed on page ${pagesSynced + 1}: ${error.message}")
throw error
}
)
}

logger.d("Local catalog variations sync completed, variations synced across $pagesSynced pages")
return Pair(
variations.toList(),
requireNotNull(firstPageServerDate) { "Can't be null since we throw an exception in the store layer." }
)
}

private fun processPageResult(
syncResult: WooPosVariationsFetchResult,
pagesSynced: Int,
maxPages: Int
) {
if (pagesSynced == 0) {
if (syncResult.totalPages > maxPages) {
logger.e(
"Local Catalog variations too large: ${syncResult.totalPages} pages exceed maximum " +
"of $maxPages pages"
)
throw CatalogTooLargeException(syncResult.totalPages, maxPages)
}
}
logger.d("Local Catalog variations page ${pagesSynced + 1} synced, ${syncResult.syncedCount} variations")
}

private fun handleTransactionError(error: Throwable): WooPosSyncVariationsResult {
return when (error) {
is CatalogTooLargeException -> {
logger.e("Local Catalog variations too large, transaction rolled back")
error.toSyncResult()
}

else -> {
logger.e("Local Catalog Variations Transaction failed and was rolled back: ${error.message}")
WooPosSyncVariationsResult.Failed.UnexpectedError(
error.message ?: "Local Catalog Variations Transaction failed and was rolled back"
)
}
}
}

internal class CatalogTooLargeException(
val totalPages: Int,
val maxPages: Int
) : Exception("Local Catalog variations too large: $totalPages pages exceed maximum of $maxPages pages") {
fun toSyncResult(): WooPosSyncVariationsResult.Failed.CatalogTooLarge {
return WooPosSyncVariationsResult.Failed.CatalogTooLarge(totalPages, maxPages)
}
}
}

This file was deleted.

Loading
Loading