Skip to content

Commit 4f8417e

Browse files
committed
Add helper to check if customs form is required
1 parent 02a45f0 commit 4f8417e

File tree

5 files changed

+83
-55
lines changed

5 files changed

+83
-55
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import Yosemite
2+
3+
struct WooShippingCustomsRequirements {
4+
/// Checks whether a customs form is required for the given origin country/state and destination country/state.
5+
///
6+
static func isCustomsRequired(originCountry: String?,
7+
originState: String?,
8+
destinationCountry: String?,
9+
destinationState: String?) -> Bool {
10+
// Special case: Any shipment from/to military addresses must have Customs
11+
if originCountry == Constants.usCountryCode,
12+
Constants.usMilitaryStates.contains(where: { $0 == originState }) {
13+
return true
14+
}
15+
if destinationCountry == Constants.usCountryCode,
16+
Constants.usMilitaryStates.contains(where: { $0 == destinationState }) {
17+
return true
18+
}
19+
20+
return originCountry != destinationCountry
21+
}
22+
}
23+
24+
private extension WooShippingCustomsRequirements {
25+
enum Constants {
26+
/// Country code for US - to check for international shipment
27+
///
28+
static let usCountryCode = "US"
29+
30+
/// These US states are a special case because they represent military bases. They're considered "domestic",
31+
/// but they require a Customs form to ship from/to them.
32+
static let usMilitaryStates = ["AA", "AE", "AP"]
33+
}
34+
}

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

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ final class WooShippingEditAddressViewModel: ObservableObject, Identifiable {
6565
/// This is used to determine whether the phone number is required when editing a destination address.
6666
private let originCountryCode: String?
6767

68+
/// The origin address state code.
69+
/// This is used to determine whether the phone number is required when editing a destination address.
70+
private let originStateCode: String?
71+
6872
/// Status of the address, based on local validation and remote verification.
6973
var status: WooShippingAddressStatus {
7074
let isRemotelyVerified = originalAddressIsVerified && !hasChanges
@@ -132,7 +136,7 @@ final class WooShippingEditAddressViewModel: ObservableObject, Identifiable {
132136

133137
/// Whether the address is in the US.
134138
var isUSAddress: Bool {
135-
country.value == Constants.usCountryCode
139+
country.value == "US"
136140
}
137141

138142
/// States of the selected country.
@@ -178,6 +182,7 @@ final class WooShippingEditAddressViewModel: ObservableObject, Identifiable {
178182
showCompanyField: Bool,
179183
isVerified: Bool,
180184
originCountryCode: String? = nil,
185+
originStateCode: String? = nil,
181186
stores: StoresManager = ServiceLocator.stores,
182187
storageManager: StorageManagerType = ServiceLocator.storageManager,
183188
debounceDelayInSeconds: Double = 1,
@@ -206,12 +211,14 @@ final class WooShippingEditAddressViewModel: ObservableObject, Identifiable {
206211
let phoneNumberRequired = Self.phoneNumberRequired(addressType: type,
207212
selectedCountryCode: country,
208213
selectedState: state,
209-
originCountryCode: originCountryCode)
214+
originCountryCode: originCountryCode,
215+
originStateCode: originStateCode)
210216
self.phone = WooShippingAddressField(type: .phone, value: phone, required: phoneNumberRequired, validate: { _ in return nil})
211217
self.isDefaultAddress = isDefaultAddress
212218
self.showCompanyField = showCompanyField
213219
self.originalAddressIsVerified = isVerified
214220
self.originCountryCode = originCountryCode
221+
self.originStateCode = originStateCode
215222
self.stores = stores
216223
self.siteID = stores.sessionManager.defaultStoreID ?? Int64.min
217224
self.storageManager = storageManager
@@ -281,6 +288,7 @@ final class WooShippingEditAddressViewModel: ObservableObject, Identifiable {
281288
email: String?,
282289
isVerified: Bool,
283290
originCountryCode: String?,
291+
originStateCode: String?,
284292
stores: StoresManager = ServiceLocator.stores,
285293
storageManager: StorageManagerType = ServiceLocator.storageManager,
286294
onAddressEdited: ((WooShippingAddress, String?) -> Void)? = nil) {
@@ -299,6 +307,7 @@ final class WooShippingEditAddressViewModel: ObservableObject, Identifiable {
299307
showCompanyField: address?.company.isNotEmpty == true,
300308
isVerified: isVerified,
301309
originCountryCode: originCountryCode,
310+
originStateCode: originStateCode,
302311
stores: stores,
303312
storageManager: storageManager,
304313
onDestinationAddressEdited: onAddressEdited)
@@ -395,10 +404,7 @@ extension WooShippingEditAddressViewModel {
395404
///
396405
private var isPhoneNumberValid: Bool {
397406
guard phone.value.isNotEmpty else {
398-
return !Self.phoneNumberRequired(addressType: addressType,
399-
selectedCountryCode: country.value,
400-
selectedState: state.value,
401-
originCountryCode: originCountryCode)
407+
return !phoneNumberRequired(for: country.value, and: state.value)
402408
}
403409
guard isUSAddress else {
404410
return true
@@ -411,24 +417,35 @@ extension WooShippingEditAddressViewModel {
411417
}
412418
}
413419

420+
/// Whether the phone number is required.
421+
///
422+
private func phoneNumberRequired(for country: String?, and state: String?) -> Bool {
423+
Self.phoneNumberRequired(addressType: addressType,
424+
selectedCountryCode: country,
425+
selectedState: state,
426+
originCountryCode: originCountryCode,
427+
originStateCode: originStateCode)
428+
}
429+
414430
/// Whether the phone number is required.
415431
/// - Parameters:
416432
/// - addressType: Type of address being edited.
417433
/// - selectedCountryCode: Country code of the selected country for the address being edited.
418434
/// - selectedState: Selected state for the address being edited.
419435
/// - originCountryCode: Country code of the origin address.
436+
/// - originStateCode: State code of the origin address.
420437
private static func phoneNumberRequired(addressType: AddressType,
421438
selectedCountryCode: String?,
422439
selectedState: String?,
423-
originCountryCode: String?) -> Bool {
440+
originCountryCode: String?,
441+
originStateCode: String?) -> Bool {
424442
if addressType == .origin {
425443
return true
426444
} else {
427-
if selectedCountryCode == Constants.usCountryCode,
428-
Constants.usMilitaryStates.contains(where: { $0 == selectedState }) {
429-
return true
430-
}
431-
return originCountryCode != selectedCountryCode
445+
return WooShippingCustomsRequirements.isCustomsRequired(originCountry: originCountryCode,
446+
originState: originStateCode,
447+
destinationCountry: selectedCountryCode,
448+
destinationState: selectedState)
432449
}
433450
}
434451
}
@@ -469,10 +486,7 @@ private extension WooShippingEditAddressViewModel {
469486
state.required = stateRequired
470487

471488
// 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)
489+
phone.required = phoneNumberRequired(for: selectedCountry.code, and: selectedState?.code)
476490
phone.validateField()
477491
}
478492
.store(in: &cancellables)
@@ -487,10 +501,7 @@ private extension WooShippingEditAddressViewModel {
487501
state.setDisplayValue(selectedState?.name ?? "")
488502

489503
// 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)
504+
phone.required = phoneNumberRequired(for: country.value, and: selectedState?.code)
494505
phone.validateField()
495506
}
496507
.store(in: &cancellables)
@@ -592,14 +603,6 @@ private extension WooShippingEditAddressViewModel {
592603
"FM", // Micronesia
593604
"MP" // Northern Mariana Islands
594605
]
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"]
603606
}
604607
}
605608

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

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -152,17 +152,10 @@ final class WooShippingCreateLabelsViewModel: ObservableObject {
152152
let destinationAddress = destinationAddress else {
153153
return false
154154
}
155-
// Special case: Any shipment from/to military addresses must have Customs
156-
if originAddress.country == Constants.usCountryCode,
157-
Constants.usMilitaryStates.contains(where: { $0 == originAddress.state }) {
158-
return true
159-
}
160-
if destinationAddress.country == Constants.usCountryCode,
161-
Constants.usMilitaryStates.contains(where: { $0 == destinationAddress.state }) {
162-
return true
163-
}
164-
165-
return originAddress.country != destinationAddress.country
155+
return WooShippingCustomsRequirements.isCustomsRequired(originCountry: originAddress.country,
156+
originState: originAddress.state,
157+
destinationCountry: destinationAddress.country,
158+
destinationState: destinationAddress.state)
166159
}
167160

168161
/// Initialize the view model without an existing shipping label.
@@ -287,6 +280,7 @@ final class WooShippingCreateLabelsViewModel: ObservableObject {
287280
email: destinationEmail,
288281
isVerified: destinationAddressStatus == .verified,
289282
originCountryCode: selectedOriginAddress?.country,
283+
originStateCode: selectedOriginAddress?.state,
290284
onAddressEdited: { [weak self] editedAddress, editedEmail in
291285
guard let self else {
292286
return
@@ -478,16 +472,6 @@ private extension WooShippingCreateLabelsViewModel {
478472
comment: "Notice when a destination address is missing on the shipping label creation screen")
479473
}
480474
}
481-
482-
enum Constants {
483-
/// Country code for US - to check for international shipment
484-
///
485-
static let usCountryCode = "US"
486-
487-
/// These US states are a special case because they represent military bases. They're considered "domestic",
488-
/// but they require a Customs form to ship from/to them.
489-
static let usMilitaryStates = ["AA", "AE", "AP"]
490-
}
491475
}
492476

493477
private extension WooShippingOriginAddress {

WooCommerce/WooCommerce.xcodeproj/project.pbxproj

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2382,6 +2382,7 @@
23822382
CEA9C8E02B6D323A000FE114 /* AnalyticsWebReportTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEA9C8DF2B6D323A000FE114 /* AnalyticsWebReportTests.swift */; };
23832383
CEAB739C2C81E3F600A7EB39 /* WooShippingCreateLabelsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEAB739B2C81E3F600A7EB39 /* WooShippingCreateLabelsView.swift */; };
23842384
CEAEB75A2CD0F9A300C3E117 /* WooShippingPostPurchaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEAEB7592CD0F9A300C3E117 /* WooShippingPostPurchaseView.swift */; };
2385+
CEB739502D6897C700411231 /* WooShippingCustomsRequirements.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEB7394F2D6897C300411231 /* WooShippingCustomsRequirements.swift */; };
23852386
CEC3CC6B2C92FDB700B93FBE /* WooShippingItemRowViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC3CC6A2C92FDB700B93FBE /* WooShippingItemRowViewModel.swift */; };
23862387
CEC3CC6D2C93127300B93FBE /* WooShippingItemsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC3CC6C2C93127300B93FBE /* WooShippingItemsViewModel.swift */; };
23872388
CEC3CC6F2C93146700B93FBE /* WooShippingCreateLabelsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC3CC6E2C93146700B93FBE /* WooShippingCreateLabelsViewModel.swift */; };
@@ -2585,9 +2586,9 @@
25852586
DE02ABBE2B578D0E008E0AC4 /* CreditCardType.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE02ABBD2B578D0E008E0AC4 /* CreditCardType.swift */; };
25862587
DE02ABC02B57D333008E0AC4 /* BlazeConfirmPaymentViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE02ABBF2B57D333008E0AC4 /* BlazeConfirmPaymentViewModelTests.swift */; };
25872588
DE02ABC22B5903AB008E0AC4 /* BlazeCampaignCreationErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE02ABC12B5903AB008E0AC4 /* BlazeCampaignCreationErrorView.swift */; };
2588-
DE06D6602D64699D00419FFA /* AuthenticatedWebViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE06D65F2D64699D00419FFA /* AuthenticatedWebViewModelTests.swift */; };
25892589
DE02C65C2D5A0B9F0089850D /* FailedProductImageCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE02C65B2D5A0B9F0089850D /* FailedProductImageCollectionViewCell.swift */; };
25902590
DE02C65E2D5A0C5D0089850D /* FailedProductImageCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DE02C65D2D5A0C5D0089850D /* FailedProductImageCollectionViewCell.xib */; };
2591+
DE06D6602D64699D00419FFA /* AuthenticatedWebViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE06D65F2D64699D00419FFA /* AuthenticatedWebViewModelTests.swift */; };
25912592
DE0A2EAA281BA083007A8015 /* ProductCategoryList.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0A2EA9281BA083007A8015 /* ProductCategoryList.swift */; };
25922593
DE0A2EAD281BA1FA007A8015 /* ProductCategorySelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0A2EAC281BA1FA007A8015 /* ProductCategorySelector.swift */; };
25932594
DE0A2EAF281BA278007A8015 /* ProductCategorySelectorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0A2EAE281BA278007A8015 /* ProductCategorySelectorViewModel.swift */; };
@@ -5576,6 +5577,7 @@
55765577
CEA9C8DF2B6D323A000FE114 /* AnalyticsWebReportTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsWebReportTests.swift; sourceTree = "<group>"; };
55775578
CEAB739B2C81E3F600A7EB39 /* WooShippingCreateLabelsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WooShippingCreateLabelsView.swift; sourceTree = "<group>"; };
55785579
CEAEB7592CD0F9A300C3E117 /* WooShippingPostPurchaseView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WooShippingPostPurchaseView.swift; sourceTree = "<group>"; };
5580+
CEB7394F2D6897C300411231 /* WooShippingCustomsRequirements.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WooShippingCustomsRequirements.swift; sourceTree = "<group>"; };
55795581
CEC3CC6A2C92FDB700B93FBE /* WooShippingItemRowViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WooShippingItemRowViewModel.swift; sourceTree = "<group>"; };
55805582
CEC3CC6C2C93127300B93FBE /* WooShippingItemsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WooShippingItemsViewModel.swift; sourceTree = "<group>"; };
55815583
CEC3CC6E2C93146700B93FBE /* WooShippingCreateLabelsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WooShippingCreateLabelsViewModel.swift; sourceTree = "<group>"; };
@@ -5782,9 +5784,9 @@
57825784
DE02ABBD2B578D0E008E0AC4 /* CreditCardType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreditCardType.swift; sourceTree = "<group>"; };
57835785
DE02ABBF2B57D333008E0AC4 /* BlazeConfirmPaymentViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlazeConfirmPaymentViewModelTests.swift; sourceTree = "<group>"; };
57845786
DE02ABC12B5903AB008E0AC4 /* BlazeCampaignCreationErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlazeCampaignCreationErrorView.swift; sourceTree = "<group>"; };
5785-
DE06D65F2D64699D00419FFA /* AuthenticatedWebViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticatedWebViewModelTests.swift; sourceTree = "<group>"; };
57865787
DE02C65B2D5A0B9F0089850D /* FailedProductImageCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FailedProductImageCollectionViewCell.swift; sourceTree = "<group>"; };
57875788
DE02C65D2D5A0C5D0089850D /* FailedProductImageCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FailedProductImageCollectionViewCell.xib; sourceTree = "<group>"; };
5789+
DE06D65F2D64699D00419FFA /* AuthenticatedWebViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticatedWebViewModelTests.swift; sourceTree = "<group>"; };
57885790
DE0A2EA9281BA083007A8015 /* ProductCategoryList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductCategoryList.swift; sourceTree = "<group>"; };
57895791
DE0A2EAC281BA1FA007A8015 /* ProductCategorySelector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductCategorySelector.swift; sourceTree = "<group>"; };
57905792
DE0A2EAE281BA278007A8015 /* ProductCategorySelectorViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductCategorySelectorViewModel.swift; sourceTree = "<group>"; };
@@ -11170,6 +11172,7 @@
1117011172
B90DD08C2D12FA6600EFC06A /* WooShipping Customs */ = {
1117111173
isa = PBXGroup;
1117211174
children = (
11175+
CEB7394F2D6897C300411231 /* WooShippingCustomsRequirements.swift */,
1117311176
B90D217F2D1ED1DE00ED60ED /* WooShippingCustomsItemOriginCountryInfoDialog.swift */,
1117411177
B90D217D2D1ECA1F00ED60ED /* WooShippingCustomsItemDescriptionInfoDialog.swift */,
1117511178
B90D217B2D1B06F600ED60ED /* WooShippingCustomsItemViewModel.swift */,
@@ -15446,6 +15449,7 @@
1544615449
8602BC9F2B19AE48001EDF20 /* ProfilerThemesPickerView.swift in Sources */,
1544715450
B6F3796E293796BC00718561 /* AnalyticsHubWeekToDateRangeData.swift in Sources */,
1544815451
DE77889A26FD7EF0008DFF44 /* ShippingLabelPackageItem.swift in Sources */,
15452+
CEB739502D6897C700411231 /* WooShippingCustomsRequirements.swift in Sources */,
1544915453
CE85535D209B5BB700938BDC /* OrderDetailsViewModel.swift in Sources */,
1545015454
31B05523264B3C8900134D87 /* CardPresentModalConnectingToReader.swift in Sources */,
1545115455
01F42C182CE34AD2003D0A5A /* CardPresentModalSuccessEmailSent.swift in Sources */,

0 commit comments

Comments
 (0)