Skip to content

Commit a4105ff

Browse files
Merge pull request #14746 from woocommerce/issue/WOOMOB-1503-mapping-from-orders
[CIAB] Implement mapping of payment details for Bookings and improve address formatting
2 parents bb99aa2 + 6d76166 commit a4105ff

File tree

12 files changed

+156
-112
lines changed

12 files changed

+156
-112
lines changed

WooCommerce/src/main/kotlin/com/woocommerce/android/model/Address.kt

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ import com.google.i18n.addressinput.common.FormOptions
66
import com.google.i18n.addressinput.common.FormatInterpreter
77
import com.woocommerce.android.extensions.appendWithIfNotEmpty
88
import com.woocommerce.android.ui.addressformatting.presentationName
9+
import com.woocommerce.android.util.AddressUtils
910
import com.woocommerce.android.util.WooLog
1011
import com.woocommerce.android.util.WooLog.T
1112
import kotlinx.parcelize.Parcelize
1213
import org.wordpress.android.fluxc.model.order.OrderAddress
1314
import org.wordpress.android.fluxc.model.shippinglabels.WCShippingLabelModel.ShippingLabelAddress
1415

15-
@Suppress("TooManyFunctions")
1616
@Parcelize
1717
data class Address(
1818
val company: String,
@@ -48,7 +48,7 @@ data class Address(
4848
.build()
4949
}
5050

51-
fun getEnvelopeAddress(): String {
51+
private fun getEnvelopeAddress(): String {
5252
return getAddressData().takeIf { it.postalCountry != null }?.let {
5353
val formatInterpreter = FormatInterpreter(FormOptions().createSnapshot())
5454
try {
@@ -63,12 +63,13 @@ data class Address(
6363
} ?: this.orderAddressToString()
6464
}
6565

66-
fun getFullAddress(name: String, address: String, country: String): String {
67-
var fullAddr = ""
68-
if (name.isNotBlank()) fullAddr += "$name\n"
69-
if (address.isNotBlank()) fullAddr += "$address\n"
70-
if (country.isNotBlank()) fullAddr += country
71-
return fullAddr
66+
fun getFullAddress(): String {
67+
return buildString {
68+
appendWithIfNotEmpty("$firstName $lastName".trim(), "\n")
69+
appendWithIfNotEmpty(getEnvelopeAddress(), "\n")
70+
val countryName = AddressUtils.getCountryLabelByCountryCode(country.code)
71+
appendWithIfNotEmpty(countryName, "\n")
72+
}
7273
}
7374

7475
fun hasInfo(): Boolean {

WooCommerce/src/main/kotlin/com/woocommerce/android/model/CustomerWithAnalytics.kt

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package com.woocommerce.android.model
33
import android.os.Parcelable
44
import com.woocommerce.android.ui.orders.creation.customerlist.CustomerListRepository
55
import com.woocommerce.android.ui.orders.creation.customerlist.CustomerListViewModelMapper
6-
import com.woocommerce.android.util.AddressUtils
76
import kotlinx.parcelize.Parcelize
87
import org.wordpress.android.fluxc.model.customer.WCCustomerModel
98

@@ -25,27 +24,10 @@ data class CustomerWithAnalytics(
2524
val shippingAddress: Address
2625
) : Parcelable {
2726
fun getFullName() = "$firstName $lastName"
28-
fun getShippingAddress(): String {
29-
val shippingName = "$firstName $lastName"
30-
val shippingAddress = this.shippingAddress.getEnvelopeAddress()
31-
val shippingCountry = AddressUtils.getCountryLabelByCountryCode(this.shippingAddress.country.code)
32-
return this.shippingAddress.getFullAddress(
33-
shippingName,
34-
shippingAddress,
35-
shippingCountry
36-
)
37-
}
3827

39-
fun getBillingAddress(): String {
40-
val shippingName = "$firstName $lastName"
41-
val shippingAddress = this.billingAddress.getEnvelopeAddress()
42-
val shippingCountry = AddressUtils.getCountryLabelByCountryCode(this.billingAddress.country.code)
43-
return this.billingAddress.getFullAddress(
44-
shippingName,
45-
shippingAddress,
46-
shippingCountry
47-
)
48-
}
28+
fun getShippingAddress(): String = shippingAddress.getFullAddress()
29+
30+
fun getBillingAddress(): String = billingAddress.getFullAddress()
4931
}
5032

5133
fun WCCustomerModel.toCustomerWithAnalytics(

WooCommerce/src/main/kotlin/com/woocommerce/android/model/Order.kt

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import com.woocommerce.android.extensions.sumByFloat
77
import com.woocommerce.android.model.Order.OrderStatus
88
import com.woocommerce.android.ui.orders.creation.configuration.ProductConfiguration
99
import com.woocommerce.android.ui.products.ProductHelper
10-
import com.woocommerce.android.util.AddressUtils
1110
import kotlinx.parcelize.IgnoredOnParcel
1211
import kotlinx.parcelize.Parcelize
1312
import org.wordpress.android.fluxc.model.WCOrderStatusModel
@@ -293,27 +292,9 @@ data class Order(
293292
}
294293
}
295294

296-
fun formatBillingInformationForDisplay(): String {
297-
val billingName = getBillingName("")
298-
val billingAddress = this.billingAddress.getEnvelopeAddress()
299-
val billingCountry = AddressUtils.getCountryLabelByCountryCode(this.billingAddress.country.code)
300-
return this.billingAddress.getFullAddress(
301-
billingName,
302-
billingAddress,
303-
billingCountry
304-
)
305-
}
295+
fun formatBillingInformationForDisplay(): String = this.billingAddress.getFullAddress()
306296

307-
fun formatShippingInformationForDisplay(): String {
308-
val shippingName = "${shippingAddress.firstName} ${shippingAddress.lastName}"
309-
val shippingAddress = this.shippingAddress.getEnvelopeAddress()
310-
val shippingCountry = AddressUtils.getCountryLabelByCountryCode(this.shippingAddress.country.code)
311-
return this.shippingAddress.getFullAddress(
312-
shippingName,
313-
shippingAddress,
314-
shippingCountry
315-
)
316-
}
297+
fun formatShippingInformationForDisplay(): String = this.shippingAddress.getFullAddress()
317298

318299
fun getProductIds() = items.map { it.productId }
319300

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/BookingMapper.kt

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
11
package com.woocommerce.android.ui.bookings
22

3+
import com.woocommerce.android.extensions.isNotEqualTo
4+
import com.woocommerce.android.model.Address
5+
import com.woocommerce.android.model.GetLocations
36
import com.woocommerce.android.ui.bookings.compose.BookingAppointmentDetailsModel
47
import com.woocommerce.android.ui.bookings.compose.BookingAttendanceStatus
58
import com.woocommerce.android.ui.bookings.compose.BookingCustomerDetailsModel
9+
import com.woocommerce.android.ui.bookings.compose.BookingPaymentDetailsModel
610
import com.woocommerce.android.ui.bookings.compose.BookingStatus
711
import com.woocommerce.android.ui.bookings.compose.BookingSummaryModel
812
import com.woocommerce.android.ui.bookings.list.BookingListItem
913
import com.woocommerce.android.util.CurrencyFormatter
14+
import kotlinx.coroutines.Dispatchers
15+
import kotlinx.coroutines.withContext
1016
import org.wordpress.android.fluxc.network.rest.wpcom.wc.bookings.BookingCustomerInfo
17+
import org.wordpress.android.fluxc.network.rest.wpcom.wc.bookings.BookingPaymentInfo
1118
import org.wordpress.android.fluxc.persistence.entity.BookingEntity
19+
import java.math.BigDecimal
1220
import java.time.Duration
1321
import java.time.ZoneOffset
1422
import java.time.format.DateTimeFormatter
@@ -17,6 +25,7 @@ import javax.inject.Inject
1725

1826
class BookingMapper @Inject constructor(
1927
private val currencyFormatter: CurrencyFormatter,
28+
private val getLocations: GetLocations
2029
) {
2130
private val summaryDateFormatter: DateTimeFormatter = DateTimeFormatter.ofLocalizedDateTime(
2231
FormatStyle.MEDIUM,
@@ -58,19 +67,28 @@ class BookingMapper @Inject constructor(
5867
)
5968
}
6069

61-
fun BookingCustomerInfo?.toCustomerDetailsModel(): BookingCustomerDetailsModel {
70+
suspend fun BookingCustomerInfo?.toCustomerDetailsModel(): BookingCustomerDetailsModel {
6271
if (this == null) return BookingCustomerDetailsModel.EMPTY
6372

6473
return BookingCustomerDetailsModel(
6574
name = fullName(),
6675
email = billingEmail,
6776
phone = billingPhone,
68-
billingAddressLines = listOfNotNull(
69-
billingAddress1,
70-
billingAddress2,
71-
listOfNotNull(billingCity, billingState, billingPostcode).takeIf { it.isNotEmpty() }?.joinToString(" "),
72-
billingCountry
73-
)
77+
billingAddress = address()?.getFullAddress()
78+
)
79+
}
80+
81+
fun BookingPaymentInfo.toPaymentDetailsModel(currency: String): BookingPaymentDetailsModel {
82+
val discount = total - subtotal
83+
return BookingPaymentDetailsModel(
84+
service = currencyFormatter.formatCurrency(subtotal, currency), // Pre-discount subtotal
85+
tax = currencyFormatter.formatCurrency(totalTax, currency), // Tax on total after discount
86+
discount = if (discount.isNotEqualTo(BigDecimal.ZERO)) {
87+
"- ${currencyFormatter.formatCurrency(discount.abs(), currency)}"
88+
} else {
89+
"-"
90+
},
91+
total = currencyFormatter.formatCurrency(total + totalTax, currency) // Total including tax
7492
)
7593
}
7694

@@ -87,4 +105,24 @@ class BookingMapper @Inject constructor(
87105
private fun BookingCustomerInfo.fullName(): String? {
88106
return "${billingFirstName.orEmpty()} ${billingLastName.orEmpty()}".trim().ifEmpty { null }
89107
}
108+
109+
private suspend fun BookingCustomerInfo.address(): Address? {
110+
val countryCode = billingCountry ?: return null
111+
val (country, state) = withContext(Dispatchers.IO) {
112+
getLocations(countryCode, billingState.orEmpty())
113+
}
114+
return Address(
115+
company = billingCompany.orEmpty(),
116+
firstName = billingFirstName.orEmpty(),
117+
lastName = billingLastName.orEmpty(),
118+
phone = billingPhone.orEmpty(),
119+
country = country,
120+
state = state,
121+
address1 = billingAddress1.orEmpty(),
122+
address2 = billingAddress2.orEmpty(),
123+
city = billingCity.orEmpty(),
124+
postcode = billingPostcode.orEmpty(),
125+
email = billingEmail.orEmpty()
126+
)
127+
}
90128
}

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/compose/BookingCustomerDetails.kt

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import androidx.compose.foundation.clickable
55
import androidx.compose.foundation.layout.Box
66
import androidx.compose.foundation.layout.Column
77
import androidx.compose.foundation.layout.Row
8+
import androidx.compose.foundation.layout.Spacer
89
import androidx.compose.foundation.layout.fillMaxWidth
910
import androidx.compose.foundation.layout.height
1011
import androidx.compose.foundation.layout.padding
@@ -81,19 +82,18 @@ fun BookingCustomerDetails(
8182
modifier = Modifier.clickable { phoneMenuExpanded = true }
8283
)
8384
}
84-
if (model.billingAddressLines.isNotEmpty()) {
85+
model.billingAddress?.let { billingAddress ->
8586
Column(
8687
modifier = Modifier
8788
.padding(vertical = 12.dp, horizontal = 16.dp)
8889
) {
8990
BookingDetailsLabel(label = R.string.booking_billing_address_label)
90-
model.billingAddressLines.forEach { line ->
91-
Text(
92-
text = line,
93-
style = MaterialTheme.typography.labelLarge,
94-
color = MaterialTheme.colorScheme.onSurfaceVariant,
95-
)
96-
}
91+
Spacer(Modifier.height(4.dp))
92+
Text(
93+
text = billingAddress,
94+
style = MaterialTheme.typography.labelLarge,
95+
color = MaterialTheme.colorScheme.onSurfaceVariant,
96+
)
9797
}
9898
HorizontalDivider(thickness = 0.5.dp)
9999
}
@@ -148,14 +148,14 @@ data class BookingCustomerDetailsModel(
148148
val name: String?,
149149
val email: String?,
150150
val phone: String?,
151-
val billingAddressLines: List<String>,
151+
val billingAddress: String?,
152152
) {
153153
companion object {
154154
val EMPTY = BookingCustomerDetailsModel(
155155
name = null,
156156
email = null,
157157
phone = null,
158-
billingAddressLines = emptyList()
158+
billingAddress = null
159159
)
160160
}
161161
}
@@ -169,11 +169,11 @@ private fun BookingCustomerDetailsPreview() {
169169
name = "Margarita Nikolaevna",
170170
email = "[email protected]",
171171
phone = "+1 555-123-4567",
172-
billingAddressLines = listOf(
173-
"238 Willow Creek Drive",
174-
"Montgomery",
175-
"AL 36109"
176-
)
172+
billingAddress = """
173+
238 Willow Creek Drive
174+
Montgomery
175+
AL 36109
176+
""".trimIndent()
177177
),
178178
modifier = Modifier.fillMaxWidth()
179179
)

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/details/BookingDetailsScreen.kt

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -138,14 +138,16 @@ private fun BookingDetailsContent(
138138
onClick = onAttendanceStatusClicked,
139139
modifier = Modifier.fillMaxWidth()
140140
)
141-
BookingPaymentSection(
142-
model = booking.bookingPaymentDetails,
143-
status = booking.bookingSummary.status,
144-
onMarkAsPaid = { onViewOrder(booking.orderId) },
145-
onViewOrder = { onViewOrder(booking.orderId) },
146-
onMarkAsRefunded = { onViewOrder(booking.orderId) },
147-
modifier = Modifier.fillMaxWidth()
148-
)
141+
booking.bookingPaymentDetails?.let {
142+
BookingPaymentSection(
143+
model = it,
144+
status = booking.bookingSummary.status,
145+
onMarkAsPaid = { onViewOrder(booking.orderId) },
146+
onViewOrder = { onViewOrder(booking.orderId) },
147+
onMarkAsRefunded = { onViewOrder(booking.orderId) },
148+
modifier = Modifier.fillMaxWidth()
149+
)
150+
}
149151
}
150152

151153
@Composable
@@ -229,11 +231,11 @@ private fun BookingDetailsPreview() {
229231
name = "Margarita Nikolaevna",
230232
email = "[email protected]",
231233
phone = "+1 555-123-4567",
232-
billingAddressLines = listOf(
233-
"238 Willow Creek Drive",
234-
"Montgomery AL 36109",
235-
"United States"
236-
)
234+
billingAddress = """
235+
238 Willow Creek Drive
236+
Montgomery AL 36109
237+
United States
238+
""".trimIndent()
237239
),
238240
bookingPaymentDetails = BookingPaymentDetailsModel(
239241
service = "$55.00",

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/details/BookingDetailsViewModel.kt

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import com.woocommerce.android.ui.bookings.Booking
88
import com.woocommerce.android.ui.bookings.BookingMapper
99
import com.woocommerce.android.ui.bookings.BookingsRepository
1010
import com.woocommerce.android.ui.bookings.compose.BookingAttendanceStatus
11-
import com.woocommerce.android.ui.bookings.compose.BookingPaymentDetailsModel
1211
import com.woocommerce.android.viewmodel.ResourceProvider
1312
import com.woocommerce.android.viewmodel.ScopedViewModel
1413
import com.woocommerce.android.viewmodel.navArgs
@@ -57,7 +56,7 @@ class BookingDetailsViewModel @Inject constructor(
5756
// TODO Add logic to Cancel booking
5857
}
5958

60-
private fun BookingMapper.buildBookingUiState(
59+
private suspend fun BookingMapper.buildBookingUiState(
6160
booking: Booking,
6261
attendanceStatus: BookingAttendanceStatus?
6362
): BookingUiState = BookingUiState(
@@ -71,11 +70,6 @@ class BookingDetailsViewModel @Inject constructor(
7170
},
7271
bookingsAppointmentDetails = booking.toAppointmentDetailsModel(),
7372
bookingCustomerDetails = booking.order.customerInfo.toCustomerDetailsModel(),
74-
bookingPaymentDetails = BookingPaymentDetailsModel(
75-
service = "$55.00",
76-
tax = "$4.50",
77-
discount = "-",
78-
total = "$59.50"
79-
)
73+
bookingPaymentDetails = booking.order.paymentInfo?.toPaymentDetailsModel(booking.currency)
8074
)
8175
}

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/details/BookingDetailsViewState.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@ data class BookingUiState(
2121
val bookingSummary: BookingSummaryModel,
2222
val bookingsAppointmentDetails: BookingAppointmentDetailsModel,
2323
val bookingCustomerDetails: BookingCustomerDetailsModel,
24-
val bookingPaymentDetails: BookingPaymentDetailsModel,
24+
val bookingPaymentDetails: BookingPaymentDetailsModel?,
2525
)

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/details/adapter/OrderDetailShippingLabelsAdapter.kt

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -114,24 +114,12 @@ class OrderDetailShippingLabelsAdapter(
114114

115115
// display origin address
116116
shippingLabel.originAddress?.let {
117-
viewBinding.shippingLabelItemShipFrom.setShippingLabelValue(
118-
it.getFullAddress(
119-
it.firstName,
120-
it.getEnvelopeAddress(),
121-
it.country.name
122-
)
123-
)
117+
viewBinding.shippingLabelItemShipFrom.setShippingLabelValue(it.getFullAddress())
124118
}
125119

126120
// display destination address
127121
shippingLabel.destinationAddress?.let {
128-
viewBinding.shippingLabelItemShipTo.setShippingLabelValue(
129-
it.getFullAddress(
130-
it.firstName,
131-
it.getEnvelopeAddress(),
132-
it.country.name
133-
)
134-
)
122+
viewBinding.shippingLabelItemShipTo.setShippingLabelValue(it.getFullAddress())
135123
}
136124

137125
// Shipping label package info

0 commit comments

Comments
 (0)