Skip to content

Commit 98f5ebd

Browse files
authored
Merge pull request #14171 from woocommerce/issue/WOOMOB-370-shipping-label-refund-network
[Shipping labels] Request label refund network
2 parents 3242df4 + ec27f71 commit 98f5ebd

File tree

5 files changed

+120
-0
lines changed

5 files changed

+120
-0
lines changed

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/networking/DTOs.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,8 @@ data class CustomsItemDTO(
214214
@SerializedName("product_id") val productId: Long
215215
)
216216

217+
data class RefundLabelResponseDTO(val success: Boolean)
218+
217219
private class ShipmentMapDeserializer : JsonDeserializer<ShipmentMap> {
218220
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): ShipmentMap {
219221
// Handle string-encoded JSON or direct JSON object

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/networking/WooShippingLabelRepository.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,4 +245,10 @@ class WooShippingLabelRepository @Inject constructor(
245245
shipments = shipments,
246246
shipmentIdsToUpdate = shipmentIdsToUpdate
247247
).asWooResult()
248+
249+
suspend fun refundLabel(
250+
site: SiteModel,
251+
orderId: Long,
252+
labelId: Long
253+
): WooResult<RefundLabelResponseDTO> = restClient.refundShippingLabel(orderId, labelId, site).asWooResult()
248254
}

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/networking/WooShippingLabelRestClient.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,4 +222,17 @@ class WooShippingLabelRestClient @Inject constructor(
222222

223223
return result.toWooPayload()
224224
}
225+
226+
suspend fun refundShippingLabel(
227+
orderId: Long,
228+
labelId: Long,
229+
site: SiteModel
230+
): WooPayload<RefundLabelResponseDTO> {
231+
val url = "/wcshipping/v1/label/refund/$orderId/$labelId"
232+
return wooNetwork.executePostGsonRequest(
233+
site = site,
234+
path = url,
235+
clazz = RefundLabelResponseDTO::class.java,
236+
).toWooPayload()
237+
}
225238
}

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/wooshippinglabels/refund/WooShippingLabelRefundViewModel.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import androidx.lifecycle.viewModelScope
77
import com.woocommerce.android.R
88
import com.woocommerce.android.extensions.formatToLocalizedMedium
99
import com.woocommerce.android.tools.NetworkStatus
10+
import com.woocommerce.android.tools.SelectedSite
11+
import com.woocommerce.android.ui.orders.wooshippinglabels.networking.WooShippingLabelRepository
1012
import com.woocommerce.android.util.CurrencyFormatter
1113
import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.Exit
1214
import com.woocommerce.android.viewmodel.MultiLiveEvent.Event.ShowSnackbar
@@ -23,6 +25,8 @@ import javax.inject.Inject
2325
@HiltViewModel
2426
class WooShippingLabelRefundViewModel @Inject constructor(
2527
savedState: SavedStateHandle,
28+
private val selectedSite: SelectedSite,
29+
private val repository: WooShippingLabelRepository,
2630
private val networkStatus: NetworkStatus,
2731
private val currencyFormatter: CurrencyFormatter,
2832
) : ScopedViewModel(savedState) {
@@ -56,6 +60,17 @@ class WooShippingLabelRefundViewModel @Inject constructor(
5660
if (networkStatus.isConnected()) {
5761
_viewState.update { ViewState.Loading }
5862
launch {
63+
repository.refundLabel(
64+
selectedSite.get(),
65+
arguments.orderId,
66+
arguments.shipment.labelId ?: return@launch
67+
).takeIf { it.isError.not() }?.let {
68+
triggerEvent(ShowSnackbar(R.string.shipping_label_refund_success))
69+
triggerEvent(Exit)
70+
} ?: run {
71+
triggerEvent(ShowSnackbar(R.string.order_refunds_amount_refund_error))
72+
loadDataState()
73+
}
5974
}
6075
} else {
6176
triggerEvent(ShowSnackbar(R.string.offline_error))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package com.woocommerce.android.ui.orders.wooshippinglabels.refund
2+
3+
import com.woocommerce.android.R
4+
import com.woocommerce.android.tools.NetworkStatus
5+
import com.woocommerce.android.tools.SelectedSite
6+
import com.woocommerce.android.ui.orders.wooshippinglabels.models.ShipmentUIModel
7+
import com.woocommerce.android.ui.orders.wooshippinglabels.networking.RefundLabelResponseDTO
8+
import com.woocommerce.android.ui.orders.wooshippinglabels.networking.WooShippingLabelRepository
9+
import com.woocommerce.android.viewmodel.BaseUnitTest
10+
import com.woocommerce.android.viewmodel.MultiLiveEvent.Event
11+
import kotlinx.coroutines.ExperimentalCoroutinesApi
12+
import org.assertj.core.api.Assertions.assertThat
13+
import org.junit.Before
14+
import org.mockito.kotlin.doReturn
15+
import org.mockito.kotlin.mock
16+
import org.mockito.kotlin.whenever
17+
import org.wordpress.android.fluxc.model.SiteModel
18+
import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooResult
19+
import kotlin.test.Test
20+
21+
@OptIn(ExperimentalCoroutinesApi::class)
22+
class WooShippingLabelRefundViewModelTest : BaseUnitTest() {
23+
private lateinit var viewModel: WooShippingLabelRefundViewModel
24+
private val mockOrderId = 456L
25+
private val mockLabelId = 789L
26+
val mockSite = SiteModel().apply { siteId = 123 }
27+
28+
private val selectedSite: SelectedSite = mock { on { get() } doReturn mockSite }
29+
private val repository: WooShippingLabelRepository = mock()
30+
private val networkStatus: NetworkStatus = mock { on { isConnected() } doReturn true }
31+
32+
@Before
33+
fun setup() {
34+
viewModel = WooShippingLabelRefundViewModel(
35+
WooShippingLabelRefundFragmentArgs(
36+
orderId = mockOrderId,
37+
shipment = ShipmentUIModel(
38+
localId = "0",
39+
items = emptyList(),
40+
labelId = mockLabelId
41+
)
42+
).toSavedStateHandle(),
43+
selectedSite = selectedSite,
44+
repository = repository,
45+
networkStatus = networkStatus,
46+
currencyFormatter = mock()
47+
)
48+
}
49+
50+
@Test
51+
fun `when refund is successful, show success message and exit`() = testBlocking {
52+
// Given
53+
var capturedEvents = mutableListOf<Event>()
54+
viewModel.event.observeForever { capturedEvents.add(it) }
55+
whenever(
56+
repository.refundLabel(site = mockSite, orderId = mockOrderId, labelId = mockLabelId)
57+
) doReturn WooResult(RefundLabelResponseDTO(true))
58+
59+
// When
60+
viewModel.onRefundShippingLabelButtonClicked()
61+
62+
// Then
63+
assertThat(capturedEvents.first()).isInstanceOf(Event.ShowSnackbar::class.java)
64+
assertThat((capturedEvents.first() as Event.ShowSnackbar).message)
65+
.isEqualTo(R.string.shipping_label_refund_success)
66+
assertThat(capturedEvents.last()).isEqualTo(Event.Exit)
67+
}
68+
69+
@Test
70+
fun `when refund fails, show error message`() = testBlocking {
71+
// Given
72+
var capturedEvent: Event.Exit? = null
73+
viewModel.event.observeForever { capturedEvent = it as? Event.Exit }
74+
whenever(
75+
repository.refundLabel(site = mockSite, orderId = mockOrderId, labelId = mockLabelId)
76+
) doReturn WooResult(RefundLabelResponseDTO(false))
77+
78+
// When
79+
viewModel.onRefundShippingLabelButtonClicked()
80+
81+
// Then
82+
assertThat(capturedEvent).isNotNull()
83+
}
84+
}

0 commit comments

Comments
 (0)