Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions RELEASE-NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- [*] Shipping Labels: Update mark order completed toggle on purchase form [https://github.com/woocommerce/woocommerce-ios/pull/15917]
- [*] Shipping Labels: Optimize data loading on purchase form [https://github.com/woocommerce/woocommerce-ios/pull/15919]
- [internal] Optimized assets for app size reduction [https://github.com/woocommerce/woocommerce-ios/pull/15881]
- [*] Shipping Labels: Allow dots in HS tariff number input field for customs settings [https://github.com/woocommerce/woocommerce-ios/pull/15933]

22.8
-----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ private extension WooShippingCustomsFormViewModel {
quantity: $0.itemQuantity,
value: Double($0.valuePerUnit) ?? 0,
weight: Double($0.weightPerUnit) ?? 0,
hsTariffNumber: $0.isValidTariffNumber ? $0.hsTariffNumber : "",
hsTariffNumber: $0.isValidTariffNumber ? $0.sanitizedHSTariffNumber : "",
originCountry: $0.selectedCountry?.code ?? "",
productID: $0.itemProductID
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,11 @@ final class WooShippingCustomsItemViewModel: ObservableObject {
}

var isValidTariffNumber: Bool {
guard hsTariffNumber.isNotEmpty else {
return true
}

// Check if the string contains only digits
let digitsOnly = CharacterSet.decimalDigits.isSuperset(of: CharacterSet(charactersIn: hsTariffNumber))
guard digitsOnly else { return false }
return HSTariffNumberValidator.isNumberValid(hsTariffNumber)
}

// Check the length of the string
let length = hsTariffNumber.count
return length >= 6 && length <= 12
var sanitizedHSTariffNumber: String {
HSTariffNumberValidator.sanitize(hsTariffNumber)
}

@Published var requiredInformationIsEntered: Bool = false
Expand Down Expand Up @@ -150,3 +144,41 @@ private extension WooShippingCustomsItemViewModel {
.store(in: &cancellables)
}
}

/// Follows validation logic from `woocommerce-shipping/client/utils/customs.ts`
enum HSTariffNumberValidator {
static let pattern = "^(\\d{1,2}\\.?){3,6}$"

/// Check if the HS Tariff Number is valid.
/// It should be a string of 6 to 12 digits, with optional dots in between every 2 digits.
/// - Parameter tariffNumber: The tariff number string.
/// - Returns: `Bool` if tariff number valid or not.
static func isNumberValid(_ tariffNumber: String) -> Bool {
if tariffNumber.isEmpty {
return true
}

let patternRange = tariffNumber.range(
of: pattern,
options: .regularExpression
)

if patternRange == nil {
return false
}

let digitsOnly = tariffNumber.components(
separatedBy: CharacterSet.decimalDigits.inverted
).joined()
let count = digitsOnly.count
return count >= 6 && count <= 12
}

/// Sanitize the HS Tariff Number
/// Remove all non-digit characters
/// - Parameter tariffNumber: The tariff number string.
/// - Returns: Tariff string without non-digit characters
static func sanitize(_ tariffNumber: String) -> String {
return tariffNumber.components(separatedBy: CharacterSet.decimalDigits.inverted).joined()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,41 @@ final class WooShippingCustomsItemViewModelTests: XCTestCase {
XCTAssertEqual(viewModel.hsTariffNumberTotalValue?.0, viewModel.hsTariffNumber)
XCTAssertEqual(viewModel.hsTariffNumberTotalValue?.1, Decimal(string: viewModel.valuePerUnit)! * 2)
}

func test_isNumberValid_whenGivenValidTariffNumbers_shouldReturnTrue() {
XCTAssertTrue(HSTariffNumberValidator.isNumberValid("123456"))
XCTAssertTrue(HSTariffNumberValidator.isNumberValid("12.34.56"))
XCTAssertTrue(HSTariffNumberValidator.isNumberValid("12.34.56.78"))
XCTAssertTrue(HSTariffNumberValidator.isNumberValid("12.34.56.78.90"))
XCTAssertTrue(HSTariffNumberValidator.isNumberValid("12.34.56.78.90.12"))
XCTAssertTrue(HSTariffNumberValidator.isNumberValid("123456789012"))
XCTAssertTrue(HSTariffNumberValidator.isNumberValid("12.345.678.90"))
XCTAssertTrue(HSTariffNumberValidator.isNumberValid("1.2.3.4.5.6"))
}

func test_isNumberValid_whenGivenInvalidTariffNumbers_shouldReturnFalse() {
// Less than 6 digits
XCTAssertFalse(HSTariffNumberValidator.isNumberValid("12345"))
XCTAssertFalse(HSTariffNumberValidator.isNumberValid("12.34.5"))

// More than 12 digits
XCTAssertFalse(HSTariffNumberValidator.isNumberValid("1234567890123"))
XCTAssertFalse(HSTariffNumberValidator.isNumberValid("12.34.56.78.90.123"))

// Invalid characters
XCTAssertFalse(HSTariffNumberValidator.isNumberValid("12345a"))
XCTAssertFalse(HSTariffNumberValidator.isNumberValid("12.34.5a"))

// Invalid structure
XCTAssertFalse(HSTariffNumberValidator.isNumberValid("12.34..56"))
XCTAssertFalse(HSTariffNumberValidator.isNumberValid(".123456"))
}

func test_hsTariffNumber_sanitize_whenGivenStringWithNonDigits_shouldReturnOnlyDigits() {
XCTAssertEqual(HSTariffNumberValidator.sanitize("12.34.56"), "123456")
XCTAssertEqual(HSTariffNumberValidator.sanitize("12a34b56c"), "123456")
XCTAssertEqual(HSTariffNumberValidator.sanitize("...123---456..."), "123456")
XCTAssertEqual(HSTariffNumberValidator.sanitize("123456"), "123456")
XCTAssertEqual(HSTariffNumberValidator.sanitize(""), "")
}
}