Skip to content

Commit 29f92ea

Browse files
committed
Require destination phone number when customs form is required
1 parent c73252e commit 29f92ea

File tree

4 files changed

+116
-54
lines changed

4 files changed

+116
-54
lines changed

WooCommerce/Classes/ViewRelated/Orders/Order Details/Shipping Labels/WooShipping Create Shipping Labels/WooShippingAddresses/WooShippingEditAddressView.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -429,8 +429,7 @@ private extension WooShippingEditAddressView {
429429
phone: "",
430430
isDefaultAddress: true,
431431
showCompanyField: false,
432-
isVerified: true,
433-
phoneNumberRequired: true))
432+
isVerified: true))
434433
}
435434

436435
#Preview("With Company") {
@@ -447,6 +446,5 @@ private extension WooShippingEditAddressView {
447446
phone: "",
448447
isDefaultAddress: false,
449448
showCompanyField: true,
450-
isVerified: false,
451-
phoneNumberRequired: true))
449+
isVerified: false))
452450
}

WooCommerce/Classes/ViewRelated/Orders/Order Details/Shipping Labels/WooShipping Create Shipping Labels/WooShippingAddresses/WooShippingEditAddressViewModel.swift

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,9 @@ final class WooShippingEditAddressViewModel: ObservableObject, Identifiable {
6161
[name, company, country, address, city, state, postalCode, email, phone]
6262
}
6363

64-
/// Whether the phone number is required.
65-
private let phoneNumberRequired: Bool
64+
/// The origin address country code.
65+
/// This is used to determine whether the phone number is required when editing a destination address.
66+
private let originCountryCode: String?
6667

6768
/// Status of the address, based on local validation and remote verification.
6869
var status: WooShippingAddressStatus {
@@ -131,7 +132,7 @@ final class WooShippingEditAddressViewModel: ObservableObject, Identifiable {
131132

132133
/// Whether the address is in the US.
133134
var isUSAddress: Bool {
134-
country.value == "US"
135+
country.value == Constants.usCountryCode
135136
}
136137

137138
/// States of the selected country.
@@ -176,7 +177,7 @@ final class WooShippingEditAddressViewModel: ObservableObject, Identifiable {
176177
isDefaultAddress: Bool,
177178
showCompanyField: Bool,
178179
isVerified: Bool,
179-
phoneNumberRequired: Bool,
180+
originCountryCode: String? = nil,
180181
stores: StoresManager = ServiceLocator.stores,
181182
storageManager: StorageManagerType = ServiceLocator.storageManager,
182183
debounceDelayInSeconds: Double = 1,
@@ -202,11 +203,15 @@ final class WooShippingEditAddressViewModel: ObservableObject, Identifiable {
202203
self.email = WooShippingAddressField(type: .email, value: email, required: true, validate: { newEmail in
203204
newEmail.isEmpty ? Localization.Validation.email : nil
204205
})
206+
let phoneNumberRequired = Self.phoneNumberRequired(addressType: type,
207+
selectedCountryCode: country,
208+
selectedState: state,
209+
originCountryCode: originCountryCode)
205210
self.phone = WooShippingAddressField(type: .phone, value: phone, required: phoneNumberRequired, validate: { _ in return nil})
206211
self.isDefaultAddress = isDefaultAddress
207212
self.showCompanyField = showCompanyField
208213
self.originalAddressIsVerified = isVerified
209-
self.phoneNumberRequired = phoneNumberRequired
214+
self.originCountryCode = originCountryCode
210215
self.stores = stores
211216
self.siteID = stores.sessionManager.defaultStoreID ?? Int64.min
212217
self.storageManager = storageManager
@@ -247,6 +252,7 @@ final class WooShippingEditAddressViewModel: ObservableObject, Identifiable {
247252
validateAddress()
248253
}
249254

255+
/// Used to initialize the view model with an origin address.
250256
convenience init(address: WooShippingOriginAddress,
251257
stores: StoresManager = ServiceLocator.stores,
252258
storageManager: StorageManagerType = ServiceLocator.storageManager,
@@ -265,15 +271,16 @@ final class WooShippingEditAddressViewModel: ObservableObject, Identifiable {
265271
isDefaultAddress: address.defaultAddress,
266272
showCompanyField: address.company.isNotEmpty,
267273
isVerified: address.isVerified,
268-
phoneNumberRequired: true,
269274
stores: stores,
270275
storageManager: storageManager,
271276
onOriginAddressEdited: onAddressEdited)
272277
}
273278

279+
/// Used to initialize the view model with a destination address.
274280
convenience init(address: WooShippingAddress?,
275281
email: String?,
276282
isVerified: Bool,
283+
originCountryCode: String?,
277284
stores: StoresManager = ServiceLocator.stores,
278285
storageManager: StorageManagerType = ServiceLocator.storageManager,
279286
onAddressEdited: ((WooShippingAddress, String?) -> Void)? = nil) {
@@ -291,7 +298,7 @@ final class WooShippingEditAddressViewModel: ObservableObject, Identifiable {
291298
isDefaultAddress: false,
292299
showCompanyField: address?.company.isNotEmpty == true,
293300
isVerified: isVerified,
294-
phoneNumberRequired: false, // TODO: Check phone number requirements for destination address.
301+
originCountryCode: originCountryCode,
295302
stores: stores,
296303
storageManager: storageManager,
297304
onDestinationAddressEdited: onAddressEdited)
@@ -388,7 +395,10 @@ extension WooShippingEditAddressViewModel {
388395
///
389396
private var isPhoneNumberValid: Bool {
390397
guard phone.value.isNotEmpty else {
391-
return !phoneNumberRequired
398+
return !Self.phoneNumberRequired(addressType: addressType,
399+
selectedCountryCode: country.value,
400+
selectedState: state.value,
401+
originCountryCode: originCountryCode)
392402
}
393403
guard isUSAddress else {
394404
return true
@@ -400,6 +410,27 @@ extension WooShippingEditAddressViewModel {
400410
return phoneDigits.count == 10
401411
}
402412
}
413+
414+
/// Whether the phone number is required.
415+
/// - Parameters:
416+
/// - addressType: Type of address being edited.
417+
/// - selectedCountryCode: Country code of the selected country for the address being edited.
418+
/// - selectedState: Selected state for the address being edited.
419+
/// - originCountryCode: Country code of the origin address.
420+
private static func phoneNumberRequired(addressType: AddressType,
421+
selectedCountryCode: String?,
422+
selectedState: String?,
423+
originCountryCode: String?) -> Bool {
424+
if addressType == .origin {
425+
return true
426+
} else {
427+
if selectedCountryCode == Constants.usCountryCode,
428+
Constants.usMilitaryStates.contains(where: { $0 == selectedState }) {
429+
return true
430+
}
431+
return originCountryCode != selectedCountryCode
432+
}
433+
}
403434
}
404435

405436
private extension WooShippingEditAddressViewModel {
@@ -436,6 +467,13 @@ private extension WooShippingEditAddressViewModel {
436467
country.setDisplayValue(selectedCountry.name)
437468
selectedState = nil
438469
state.required = stateRequired
470+
471+
// Update phone number requirement based on selected country.
472+
phone.required = Self.phoneNumberRequired(addressType: addressType,
473+
selectedCountryCode: selectedCountry.code,
474+
selectedState: selectedState?.code,
475+
originCountryCode: originCountryCode)
476+
phone.validateField()
439477
}
440478
.store(in: &cancellables)
441479
}
@@ -447,6 +485,13 @@ private extension WooShippingEditAddressViewModel {
447485
guard let self else { return }
448486
state.value = selectedState?.code ?? ""
449487
state.setDisplayValue(selectedState?.name ?? "")
488+
489+
// Update phone number requirement based on selected state.
490+
phone.required = Self.phoneNumberRequired(addressType: addressType,
491+
selectedCountryCode: country.value,
492+
selectedState: selectedState?.code,
493+
originCountryCode: originCountryCode)
494+
phone.validateField()
450495
}
451496
.store(in: &cancellables)
452497
}
@@ -547,6 +592,14 @@ private extension WooShippingEditAddressViewModel {
547592
"FM", // Micronesia
548593
"MP" // Northern Mariana Islands
549594
]
595+
596+
/// Country code for US - to check for international shipment
597+
///
598+
static let usCountryCode = "US"
599+
600+
/// These US states are a special case because they represent military bases. They're considered "domestic",
601+
/// but they require a Customs form to ship from/to them.
602+
static let usMilitaryStates = ["AA", "AE", "AP"]
550603
}
551604
}
552605

WooCommerce/Classes/ViewRelated/Orders/Order Details/Shipping Labels/WooShipping Create Shipping Labels/WooShippingCreateLabelsViewModel.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ final class WooShippingCreateLabelsViewModel: ObservableObject {
286286
addressToEdit = WooShippingEditAddressViewModel(address: destinationAddress,
287287
email: destinationEmail,
288288
isVerified: destinationAddressStatus == .verified,
289+
originCountryCode: selectedOriginAddress?.country,
289290
onAddressEdited: { [weak self] editedAddress, editedEmail in
290291
guard let self else {
291292
return

0 commit comments

Comments
 (0)