Skip to content

Commit

Permalink
Merge pull request #13029 from woocommerce/issue/12998-connecting-shi…
Browse files Browse the repository at this point in the history
…pping-lines

Connecting shipping lines
  • Loading branch information
atorresveiga authored Nov 29, 2024
2 parents bf61ebc + e425df2 commit 509b9c9
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ import kotlinx.coroutines.launch
@Composable
fun ShipmentDetails(
scaffoldState: BottomSheetScaffoldState,
shippableItems: ShippableItemsUI,
shippingLines: List<ShippingLineSummaryUI>,
markOrderComplete: Boolean,
onMarkOrderCompleteChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
Expand Down Expand Up @@ -98,18 +100,26 @@ fun ShipmentDetails(
}
}
if (LocalConfiguration.current.orientation == Configuration.ORIENTATION_LANDSCAPE) {
ShipmentDetailsLandscape(modifier = modifier)
ShipmentDetailsLandscape(
shippableItems = shippableItems,
shippingLines = shippingLines,
modifier = modifier
)
} else {
ShipmentDetailsPortrait(
modifier = modifier,
shippableItems = shippableItems,
shippingLines = shippingLines,
markOrderComplete = markOrderComplete,
onMarkOrderCompleteChange = onMarkOrderCompleteChange
onMarkOrderCompleteChange = onMarkOrderCompleteChange,
modifier = modifier
)
}
}

@Composable
private fun ShipmentDetailsPortrait(
shippableItems: ShippableItemsUI,
shippingLines: List<ShippingLineSummaryUI>,
markOrderComplete: Boolean,
onMarkOrderCompleteChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
Expand All @@ -126,9 +136,9 @@ private fun ShipmentDetailsPortrait(
OrderDetailsSection(
shipFrom = getShipFrom(),
shipTo = getShipTo(),
totalItems = 5,
totalItemsCost = "$120.99",
shippingLines = getShippingLines(3)
totalItems = shippableItems.shippableItems.size,
totalItemsCost = shippableItems.formattedTotalPrice,
shippingLines = shippingLines
)
Divider(modifier = Modifier.padding(horizontal = dimensionResource(R.dimen.major_100)))
ShipmentCostSection(
Expand All @@ -147,6 +157,8 @@ private fun ShipmentDetailsPortrait(

@Composable
private fun ShipmentDetailsLandscape(
shippableItems: ShippableItemsUI,
shippingLines: List<ShippingLineSummaryUI>,
modifier: Modifier = Modifier,
) {
Column(modifier) {
Expand All @@ -169,9 +181,9 @@ private fun ShipmentDetailsLandscape(
.fillMaxWidth()
) {
OrderDetailsSectionLandscape(
totalItems = 5,
totalItemsCost = "$120.99",
shippingLines = getShippingLines(3),
totalItems = shippableItems.shippableItems.size,
totalItemsCost = shippableItems.formattedTotalPrice,
shippingLines = shippingLines,
modifier = Modifier.weight(1f)
)
VerticalDivider(modifier = Modifier.padding(top = dimensionResource(R.dimen.major_100)))
Expand Down Expand Up @@ -214,7 +226,7 @@ private fun OrderDetailsSection(
shipTo: Address,
totalItems: Int,
totalItemsCost: String,
shippingLines: List<ShippingLineSummary>,
shippingLines: List<ShippingLineSummaryUI>,
modifier: Modifier = Modifier,
) {
Column(modifier.fillMaxWidth()) {
Expand All @@ -241,7 +253,7 @@ private fun OrderDetailsSection(
private fun OrderDetailsSectionLandscape(
totalItems: Int,
totalItemsCost: String,
shippingLines: List<ShippingLineSummary>,
shippingLines: List<ShippingLineSummaryUI>,
modifier: Modifier = Modifier,
) {
Column(modifier.fillMaxWidth()) {
Expand All @@ -266,7 +278,14 @@ private fun OrderDetailsSectionLandscape(
fun ShipmentDetailsLandscapePreview() {
WooThemeWithBackground {
Surface {
ShipmentDetailsLandscape()
ShipmentDetailsLandscape(
shippableItems = ShippableItemsUI(
shippableItems = generateItems(6),
formattedTotalWeight = "8.5kg",
formattedTotalPrice = "$92.78"
),
shippingLines = getShippingLines()
)
}
}
}
Expand All @@ -275,7 +294,7 @@ fun ShipmentDetailsLandscapePreview() {
private fun TotalCard(
totalItems: Int,
totalItemsCost: String,
shippingLines: List<ShippingLineSummary>,
shippingLines: List<ShippingLineSummaryUI>,
modifier: Modifier = Modifier
) {
Column(modifier) {
Expand Down Expand Up @@ -314,7 +333,7 @@ private fun ItemsCostPreview() {

@Composable
private fun ShippingLines(
shippingLines: List<ShippingLineSummary>,
shippingLines: List<ShippingLineSummaryUI>,
modifier: Modifier = Modifier
) {
Column(modifier) {
Expand Down Expand Up @@ -445,16 +464,16 @@ private fun ShipmentCostSectionPreview() {
}
}

private fun getShippingLines(number: Int = 3) = List(number) { i ->
ShippingLineSummary(
fun getShippingLines(number: Int = 3) = List(number) { i ->
ShippingLineSummaryUI(
title = "Shipping $i",
amount = "$12.99"
)
}

fun Address.toShippingFromString() = this.getEnvelopeAddress().replace("\n", " ")

data class ShippingLineSummary(
data class ShippingLineSummaryUI(
val title: String,
val amount: String
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ fun WooShippingLabelCreationScreen(viewModel: WooShippingLabelCreationViewModel)
WooShippingLabelCreationScreen(
onSelectPackageClick = viewModel::onSelectPackageClicked,
onPurchaseShippingLabel = viewModel::onPurchaseShippingLabel,
shippableItems = viewState.shippableItems
shippableItems = viewState.shippableItems,
shippingLines = viewState.shippingLines
)
}
}
Expand All @@ -70,6 +71,7 @@ fun WooShippingLabelCreationScreen(viewModel: WooShippingLabelCreationViewModel)
@Composable
fun WooShippingLabelCreationScreen(
shippableItems: ShippableItemsUI,
shippingLines: List<ShippingLineSummaryUI>,
modifier: Modifier = Modifier,
onSelectPackageClick: () -> Unit,
onPurchaseShippingLabel: () -> Unit
Expand All @@ -80,7 +82,8 @@ fun WooShippingLabelCreationScreen(
shippableItems = shippableItems,
modifier = modifier,
onSelectPackageClick = onSelectPackageClick,
scaffoldState = scaffoldState
scaffoldState = scaffoldState,
shippingLines = shippingLines
)
val isDarkTheme = isSystemInDarkTheme()
val isCollapsed = scaffoldState.bottomSheetState.isCollapsed
Expand Down Expand Up @@ -115,6 +118,7 @@ fun WooShippingLabelCreationScreen(
@Composable
private fun LabelCreationScreenWithBottomSheet(
shippableItems: ShippableItemsUI,
shippingLines: List<ShippingLineSummaryUI>,
modifier: Modifier = Modifier,
onSelectPackageClick: () -> Unit,
scaffoldState: BottomSheetScaffoldState
Expand All @@ -123,10 +127,12 @@ private fun LabelCreationScreenWithBottomSheet(
sheetContent = {
val markOrderComplete = remember { mutableStateOf(false) }
ShipmentDetails(
modifier = Modifier.padding(bottom = 74.dp),
shippableItems = shippableItems,
shippingLines = shippingLines,
scaffoldState = scaffoldState,
markOrderComplete = markOrderComplete.value,
onMarkOrderCompleteChange = { markOrderComplete.value = it }
onMarkOrderCompleteChange = { markOrderComplete.value = it },
modifier = Modifier.padding(bottom = 74.dp),
)
},
sheetPeekHeight = 132.dp,
Expand Down Expand Up @@ -204,6 +210,7 @@ private fun WooShippingLabelCreationScreenPreview() {
formattedTotalWeight = "8.5kg",
formattedTotalPrice = "$92.78"
),
shippingLines = getShippingLines(),
modifier = Modifier.fillMaxSize(),
onSelectPackageClick = {},
onPurchaseShippingLabel = {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.woocommerce.android.ui.orders.wooshippinglabels
import androidx.lifecycle.SavedStateHandle
import com.woocommerce.android.extensions.formatToString
import com.woocommerce.android.extensions.sumByFloat
import com.woocommerce.android.model.Order
import com.woocommerce.android.ui.orders.details.OrderDetailRepository
import com.woocommerce.android.ui.orders.wooshippinglabels.models.ShippableItemModel
import com.woocommerce.android.ui.orders.wooshippinglabels.models.StoreOptionsModel
Expand All @@ -12,7 +13,6 @@ import com.woocommerce.android.viewmodel.ScopedViewModel
import com.woocommerce.android.viewmodel.navArgs
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.launch
import javax.inject.Inject

Expand All @@ -37,22 +37,22 @@ class WooShippingLabelCreationViewModel @Inject constructor(
init {
launch {
orderDetailRepository.getOrderById(navArgs.orderId)?.let { order ->
shippableItems.value = getShippableItems(order)
}
}
val items = getShippableItems(order)
shippableItems.value = items

launch {
shippableItems.filter { it.isNotEmpty() }.collect { items ->
val shippableItems = items.map { item -> item.toUIModel(currencyFormatter, storeOptions) }
val shippableItemsUI = items.map { item -> item.toUIModel(currencyFormatter, storeOptions) }
val formattedTotalPrice = getTotalPrice(items)
val formattedTotalWeight = getTotalWeight(items)

val shippingLineSummary = getShippingLinesSummary(order)

viewState.value = WooShippingViewState.DataState(
shippableItems = ShippableItemsUI(
shippableItems = shippableItems,
shippableItems = shippableItemsUI,
formattedTotalWeight = formattedTotalWeight,
formattedTotalPrice = formattedTotalPrice
)
),
shippingLines = shippingLineSummary
)
}
}
Expand All @@ -71,6 +71,15 @@ class WooShippingLabelCreationViewModel @Inject constructor(
return "${totalWeight.formatToString()} ${storeOptions.weightUnit}"
}

private fun getShippingLinesSummary(order: Order): List<ShippingLineSummaryUI> {
return order.shippingLines.map {
ShippingLineSummaryUI(
title = it.methodTitle,
amount = currencyFormatter.formatCurrency(it.total, order.currency)
)
}
}

fun onSelectPackageClicked() {
triggerEvent(StartPackageSelection)
}
Expand All @@ -85,7 +94,8 @@ class WooShippingLabelCreationViewModel @Inject constructor(
sealed class WooShippingViewState {
data object Loading : WooShippingViewState()
data class DataState(
val shippableItems: ShippableItemsUI
val shippableItems: ShippableItemsUI,
val shippingLines: List<ShippingLineSummaryUI>
) : WooShippingViewState()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package com.woocommerce.android.ui.orders.wooshippinglabels

import androidx.lifecycle.SavedStateHandle
import com.woocommerce.android.model.Order
import com.woocommerce.android.ui.orders.OrderTestUtils
import com.woocommerce.android.ui.orders.details.OrderDetailRepository
import com.woocommerce.android.ui.orders.wooshippinglabels.WooShippingLabelCreationViewModel.WooShippingViewState
import com.woocommerce.android.ui.orders.wooshippinglabels.models.ShippableItemModel
import com.woocommerce.android.util.CurrencyFormatter
import com.woocommerce.android.viewmodel.BaseUnitTest
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.junit.Test
import org.mockito.kotlin.any
import org.mockito.kotlin.doAnswer
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import java.math.BigDecimal
import kotlin.test.assertEquals

@OptIn(ExperimentalCoroutinesApi::class)
class WooShippingLabelCreationViewModelTest : BaseUnitTest() {
private val orderId = 1L
private val defaultShippableItems = List(3) {
ShippableItemModel(
itemId = it.toLong(),
productId = it.toLong(),
title = "Product $it",
price = BigDecimal(it),
quantity = it.toFloat(),
weight = it.toFloat(),
currency = "USD",
imageUrl = "https://example.com/image.jpg",
width = it.toFloat(),
height = it.toFloat(),
length = it.toFloat()
)
}
private val defaultShippingLines = List(3) {
Order.ShippingLine(
methodTitle = "Shipping Line $it",
total = BigDecimal(it),
methodId = it.toString(),
itemId = it.toLong(),
totalTax = BigDecimal.ZERO,
)
}
private val orderDetailRepository: OrderDetailRepository = mock()
private val getShippableItems: GetShippableItems = mock()
private val currencyFormatter: CurrencyFormatter = mock {
on { formatCurrency(any<BigDecimal>(), any(), any()) } doAnswer {
val amount = it.getArgument(0) as BigDecimal
"$ ${amount.toPlainString()}"
}
}
private val savedState: SavedStateHandle =
WooShippingLabelCreationFragmentArgs(orderId = orderId).toSavedStateHandle()

private lateinit var sut: WooShippingLabelCreationViewModel

fun createViewModel() {
sut = WooShippingLabelCreationViewModel(
orderDetailRepository = orderDetailRepository,
getShippableItems = getShippableItems,
currencyFormatter = currencyFormatter,
savedState = savedState
)
}

@Test
fun `when the order NO contains shipping lines, then NO shipping lines summary is displayed`() = testBlocking {
val order = OrderTestUtils.generateTestOrder(orderId = orderId).copy(
shippingLines = emptyList()
)
whenever(orderDetailRepository.getOrderById(any())) doReturn order
whenever(getShippableItems(any())) doReturn defaultShippableItems

createViewModel()

val currentViewState = sut.viewState.value
assert(currentViewState is WooShippingViewState.DataState)
val dataState = currentViewState as WooShippingViewState.DataState
assert(dataState.shippingLines.isEmpty())
}

@Test
fun `when the order contains shipping lines, then shipping lines summary is displayed`() = testBlocking {
val order = OrderTestUtils.generateTestOrder(orderId = orderId).copy(
shippingLines = defaultShippingLines
)
whenever(orderDetailRepository.getOrderById(any())) doReturn order
whenever(getShippableItems(any())) doReturn defaultShippableItems

createViewModel()

val currentViewState = sut.viewState.value
assert(currentViewState is WooShippingViewState.DataState)
val dataState = currentViewState as WooShippingViewState.DataState
assert(dataState.shippingLines.isNotEmpty())
assertEquals(dataState.shippingLines.size, defaultShippingLines.size)
}
}

0 comments on commit 509b9c9

Please sign in to comment.