Skip to content

Commit 41918de

Browse files
committed
Merge branch 'trunk' into issue/woomob-1685-woo-poslocal-catalog-product-not-available-state
2 parents 3f91c05 + 7585c9f commit 41918de

File tree

16 files changed

+687
-346
lines changed

16 files changed

+687
-346
lines changed

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/data/WooPosGetOrderRefundsByOrderId.kt

Lines changed: 0 additions & 21 deletions
This file was deleted.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.woocommerce.android.ui.woopos.common.data
2+
3+
import com.woocommerce.android.model.Order
4+
import com.woocommerce.android.model.Refund
5+
import com.woocommerce.android.model.toAppModel
6+
import com.woocommerce.android.tools.SelectedSite
7+
import kotlinx.coroutines.Dispatchers
8+
import kotlinx.coroutines.withContext
9+
import org.wordpress.android.fluxc.store.WCRefundStore
10+
import java.math.BigDecimal
11+
import javax.inject.Inject
12+
13+
class WooPosRetrieveOrderRefunds @Inject constructor(
14+
private val refundStore: WCRefundStore,
15+
private val selectedSite: SelectedSite
16+
) {
17+
suspend operator fun invoke(order: Order): Result<List<Refund>> =
18+
withContext(Dispatchers.IO) {
19+
if (order.refundTotal.compareTo(BigDecimal.ZERO) == 0) {
20+
return@withContext Result.success(emptyList())
21+
}
22+
23+
val site = selectedSite.get()
24+
25+
var refundModels = refundStore.getAllRefunds(site, order.id)
26+
if (refundModels.isEmpty()) {
27+
val fetchResult = refundStore.fetchAllRefunds(site, order.id)
28+
if (fetchResult.isError) {
29+
return@withContext Result.failure(
30+
Exception("Failed to fetch refunds: ${fetchResult.error.message}")
31+
)
32+
}
33+
refundModels = fetchResult.model ?: emptyList()
34+
}
35+
36+
Result.success(refundModels.map { it.toAppModel() })
37+
}
38+
}

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/orders/WooPosOrdersDataSource.kt

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,13 @@ package com.woocommerce.android.ui.woopos.orders
22

33
import com.woocommerce.android.model.Order
44
import com.woocommerce.android.model.OrderMapper
5+
import com.woocommerce.android.model.Refund
56
import com.woocommerce.android.tools.SelectedSite
7+
import com.woocommerce.android.ui.woopos.common.data.WooPosRetrieveOrderRefunds
68
import kotlinx.coroutines.Dispatchers
9+
import kotlinx.coroutines.async
10+
import kotlinx.coroutines.awaitAll
11+
import kotlinx.coroutines.coroutineScope
712
import kotlinx.coroutines.flow.Flow
813
import kotlinx.coroutines.flow.flow
914
import kotlinx.coroutines.withContext
@@ -16,21 +21,27 @@ import java.util.concurrent.atomic.AtomicInteger
1621
import javax.inject.Inject
1722

1823
sealed class LoadOrdersResult {
19-
data class SuccessCache(val orders: List<Order>) : LoadOrdersResult()
20-
data class SuccessRemote(val orders: List<Order>) : LoadOrdersResult()
24+
data class SuccessCache(val ordersWithRefunds: Map<Order, RefundFetchResult>) : LoadOrdersResult()
25+
data class SuccessRemote(val ordersWithRefunds: Map<Order, RefundFetchResult>) : LoadOrdersResult()
2126
data class Error(val message: String) : LoadOrdersResult()
2227
}
2328

2429
sealed class SearchOrdersResult {
25-
data class Success(val orders: List<Order>) : SearchOrdersResult()
30+
data class Success(val ordersWithRefunds: Map<Order, RefundFetchResult>) : SearchOrdersResult()
2631
data class Error(val message: String) : SearchOrdersResult()
2732
}
2833

34+
sealed class RefundFetchResult {
35+
data class Success(val refunds: List<Refund>) : RefundFetchResult()
36+
object Error : RefundFetchResult()
37+
}
38+
2939
class WooPosOrdersDataSource @Inject constructor(
3040
private val restClient: OrderRestClient,
3141
private val selectedSite: SelectedSite,
3242
private val orderMapper: OrderMapper,
33-
private val ordersCache: WooPosOrdersInMemoryCache
43+
private val ordersCache: WooPosOrdersInMemoryCache,
44+
private val retrieveOrderRefunds: WooPosRetrieveOrderRefunds
3445
) {
3546
private val canLoadMore = AtomicBoolean(false)
3647
private val page = AtomicInteger(1)
@@ -45,12 +56,16 @@ class WooPosOrdersDataSource @Inject constructor(
4556

4657
fun loadOrders(): Flow<LoadOrdersResult> = flow {
4758
val cached = ordersCache.getAll()
48-
if (cached.isNotEmpty()) emit(LoadOrdersResult.SuccessCache(cached))
59+
if (cached.isNotEmpty()) {
60+
val cachedWithRefunds = fetchRefundsForOrders(cached)
61+
emit(LoadOrdersResult.SuccessCache(cachedWithRefunds))
62+
}
4963

5064
val result = loadFirstPage()
51-
result.onSuccess {
52-
ordersCache.setAll(it)
53-
emit(LoadOrdersResult.SuccessRemote(it))
65+
result.onSuccess { orders ->
66+
ordersCache.setAll(orders)
67+
val ordersWithRefunds = fetchRefundsForOrders(orders)
68+
emit(LoadOrdersResult.SuccessRemote(ordersWithRefunds))
5469
}.onFailure {
5570
emit(LoadOrdersResult.Error(it.message ?: UNKNOWN_ERROR))
5671
}
@@ -59,13 +74,20 @@ class WooPosOrdersDataSource @Inject constructor(
5974
suspend fun searchOrders(searchQuery: String): SearchOrdersResult {
6075
val result = loadFirstPage(searchQuery)
6176
return result.fold(
62-
onSuccess = { SearchOrdersResult.Success(it) },
77+
onSuccess = { orders ->
78+
val ordersWithRefunds = fetchRefundsForOrders(orders)
79+
SearchOrdersResult.Success(ordersWithRefunds)
80+
},
6381
onFailure = { SearchOrdersResult.Error(it.message ?: UNKNOWN_ERROR) }
6482
)
6583
}
6684

67-
suspend fun loadMore(searchQuery: String? = null): Result<List<Order>> =
68-
withContext(Dispatchers.IO) { loadNextPage(searchQuery) }
85+
suspend fun loadMore(searchQuery: String? = null): Result<Map<Order, RefundFetchResult>> =
86+
withContext(Dispatchers.IO) {
87+
loadNextPage(searchQuery).map { orders ->
88+
fetchRefundsForOrders(orders)
89+
}
90+
}
6991

7092
suspend fun refreshOrderById(orderId: Long): Result<Order> {
7193
val site = selectedSite.get()
@@ -135,4 +157,16 @@ class WooPosOrdersDataSource @Inject constructor(
135157

136158
private fun WCOrderStore.OrderError.toThrowable(): Throwable =
137159
Throwable("[$type] $message")
160+
161+
private suspend fun fetchRefundsForOrders(orders: List<Order>): Map<Order, RefundFetchResult> =
162+
coroutineScope {
163+
orders.map { order ->
164+
async {
165+
retrieveOrderRefunds(order).fold(
166+
onSuccess = { refunds -> order to RefundFetchResult.Success(refunds) },
167+
onFailure = { order to RefundFetchResult.Error }
168+
)
169+
}
170+
}.awaitAll().toMap()
171+
}
138172
}

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/orders/WooPosOrdersDetails.kt

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTyp
4545
@Composable
4646
fun WooPosOrderDetails(
4747
modifier: Modifier = Modifier,
48-
details: OrderDetailsViewState,
48+
details: OrderDetailsViewState.Computed.Details,
4949
onEmailReceiptButtonClicked: (Long) -> Unit
5050
) {
5151
Column(
@@ -89,7 +89,7 @@ fun WooPosOrderDetails(
8989
}
9090

9191
@Composable
92-
private fun OrdersHeader(details: OrderDetailsViewState) {
92+
private fun OrdersHeader(details: OrderDetailsViewState.Computed.Details) {
9393
Column(modifier = Modifier.fillMaxWidth()) {
9494
WooPosText(
9595
text = details.dateTime,
@@ -113,7 +113,7 @@ private fun OrdersHeader(details: OrderDetailsViewState) {
113113
}
114114

115115
@Composable
116-
private fun OrdersProducts(lineItems: List<OrderDetailsViewState.LineItemRow>) {
116+
private fun OrdersProducts(lineItems: List<OrderDetailsViewState.Computed.Details.LineItemRow>) {
117117
WooPosCard(shadowType = ShadowType.Soft) {
118118
Column(Modifier.padding(WooPosSpacing.Medium.value)) {
119119
WooPosText(
@@ -137,7 +137,7 @@ private fun OrdersProducts(lineItems: List<OrderDetailsViewState.LineItemRow>) {
137137

138138
@Composable
139139
@Suppress("DestructuringDeclarationWithTooManyEntries")
140-
private fun OrderProductItem(row: OrderDetailsViewState.LineItemRow) {
140+
private fun OrderProductItem(row: OrderDetailsViewState.Computed.Details.LineItemRow) {
141141
ConstraintLayout(
142142
modifier = Modifier
143143
.fillMaxWidth()
@@ -170,7 +170,7 @@ private fun OrderProductItem(row: OrderDetailsViewState.LineItemRow) {
170170
style = WooPosTypography.BodyMedium,
171171
color = WooPosTheme.colors.onSurfaceVariantHighest,
172172
modifier = Modifier.constrainAs(qtyText) {
173-
bottom.linkTo(image.bottom)
173+
top.linkTo(nameText.bottom, margin = WooPosSpacing.XSmall.value)
174174
start.linkTo(nameText.start)
175175
end.linkTo(totalText.start, margin = WooPosSpacing.Small.value)
176176
width = Dimension.fillToConstraints
@@ -189,7 +189,7 @@ private fun OrderProductItem(row: OrderDetailsViewState.LineItemRow) {
189189
}
190190

191191
@Composable
192-
private fun OrdersTotals(details: OrderDetailsViewState) {
192+
private fun OrdersTotals(details: OrderDetailsViewState.Computed.Details) {
193193
WooPosCard(shadowType = ShadowType.Soft) {
194194
Column(Modifier.padding(WooPosSpacing.Medium.value)) {
195195
WooPosText(
@@ -348,18 +348,25 @@ private fun DividerWithSpacing() {
348348
@WooPosPreview
349349
@Composable
350350
fun WooPosOrderDetailsPreview() {
351-
val orderDetails = OrderDetailsViewState(
351+
val orderDetails = OrderDetailsViewState.Computed.Details(
352352
id = 1L,
353353
number = "#014",
354354
dateTime = "Aug 28, 2025 at 10:31 AM",
355355
customerEmail = "[email protected]",
356356
status = PosOrderStatus(text = "Completed", colorKey = OrderStatusColorKey.COMPLETED),
357357
lineItems = listOf(
358-
OrderDetailsViewState.LineItemRow(101, "Cup", "2 x $4.00", "$8.00", null),
359-
OrderDetailsViewState.LineItemRow(102, "Coffee Container", "1 x $10.00", "$10.00", null),
360-
OrderDetailsViewState.LineItemRow(103, "Paper Filter", "1 x $5.00", "$5.00", null)
358+
OrderDetailsViewState.Computed.Details.LineItemRow(101, "Cup", "2 x $4.00", "$8.00", null),
359+
OrderDetailsViewState.Computed.Details.LineItemRow(102, "Coffee Container", "1 x $10.00", "$10.00", null),
360+
OrderDetailsViewState.Computed.Details.LineItemRow(
361+
103,
362+
"A vey tasty coffee that incidentally has a very long name " +
363+
"and should go over a few lines without overlapping anything",
364+
"1 x $5.00",
365+
"$5.00",
366+
null
367+
)
361368
),
362-
breakdown = OrderDetailsViewState.TotalsBreakdown(
369+
breakdown = OrderDetailsViewState.Computed.Details.TotalsBreakdown(
363370
products = "$23.00",
364371
discount = "-$5.00",
365372
discountCode = "SAVE5",

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/orders/WooPosOrdersLoadingState.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ fun WooPosOrdersLoadingState() {
4646
modifier = Modifier
4747
.weight(0.3f)
4848
.fillMaxHeight()
49-
.background(MaterialTheme.colorScheme.surface)
49+
.background(MaterialTheme.colorScheme.surfaceBright)
5050
.padding(top = WOO_POS_ORDERS_TOOLBAR_HEIGHT)
5151
.padding(top = WooPosSpacing.XLarge.value)
5252
)
@@ -55,7 +55,7 @@ fun WooPosOrdersLoadingState() {
5555
modifier = Modifier
5656
.weight(0.7f)
5757
.fillMaxHeight()
58-
.background(MaterialTheme.colorScheme.surfaceContainerLow)
58+
.background(MaterialTheme.colorScheme.surface)
5959
.padding(top = WooPosSpacing.Large.value)
6060
)
6161
}

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/orders/WooPosOrdersScreen.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -524,8 +524,8 @@ fun WooPosOrdersScreenPreview() {
524524
state = WooPosOrdersState.Content(
525525
items = WooPosOrdersState.Content.Items.Loaded(
526526
items = mapOf(
527-
item1 to details1,
528-
item2 to details2
527+
item1 to OrderDetailsViewState.Computed(orderId = 1L, details = details1),
528+
item2 to OrderDetailsViewState.Computed(orderId = 2L, details = details2)
529529
)
530530
),
531531
pullToRefreshState = WooPosPullToRefreshState.Enabled,
@@ -617,18 +617,18 @@ fun WooPosOrdersNothingFoundStatePreview() {
617617
private fun sampleOrderDetails(
618618
id: Long = 1L,
619619
number: String = "#014"
620-
) = OrderDetailsViewState(
620+
) = OrderDetailsViewState.Computed.Details(
621621
id = id,
622622
number = number,
623623
dateTime = "Aug 28, 2025 at 10:31 AM",
624624
customerEmail = "[email protected]",
625625
status = PosOrderStatus(text = "Completed", colorKey = OrderStatusColorKey.COMPLETED),
626626
lineItems = listOf(
627-
OrderDetailsViewState.LineItemRow(101, "Cup", "1 x $8.50", "$15.00", null),
628-
OrderDetailsViewState.LineItemRow(102, "Coffee Container", "1 x $10.00", "$8.00", null),
629-
OrderDetailsViewState.LineItemRow(103, "Paper Filter", "1 x $4.50", "$8.00", null)
627+
OrderDetailsViewState.Computed.Details.LineItemRow(101, "Cup", "1 x $8.50", "$15.00", null),
628+
OrderDetailsViewState.Computed.Details.LineItemRow(102, "Coffee Container", "1 x $10.00", "$8.00", null),
629+
OrderDetailsViewState.Computed.Details.LineItemRow(103, "Paper Filter", "1 x $4.50", "$8.00", null)
630630
),
631-
breakdown = OrderDetailsViewState.TotalsBreakdown(
631+
breakdown = OrderDetailsViewState.Computed.Details.TotalsBreakdown(
632632
products = "$23.00",
633633
discount = "-$5.00",
634634
discountCode = "8qew4mnq",

0 commit comments

Comments
 (0)