diff --git a/Networking/Networking/Model/ShippingLabel/Packages/WooShippingOriginAddress.swift b/Networking/Networking/Model/ShippingLabel/Packages/WooShippingOriginAddress.swift index 1e0d0997e07..7e1a6887fc7 100644 --- a/Networking/Networking/Model/ShippingLabel/Packages/WooShippingOriginAddress.swift +++ b/Networking/Networking/Model/ShippingLabel/Packages/WooShippingOriginAddress.swift @@ -50,7 +50,7 @@ public struct WooShippingOriginAddress: Identifiable, Equatable, GeneratedFakeab } // MARK: Decodable -extension WooShippingOriginAddress: Decodable { +extension WooShippingOriginAddress: Codable { public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) @@ -86,6 +86,24 @@ extension WooShippingOriginAddress: Decodable { isVerified: isVerified) } + public func encode(to encoder: any Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(self.id, forKey: .id) + try container.encode(self.company, forKey: .company) + try container.encode(self.address1, forKey: .address1) + try container.encode(self.address2, forKey: .address2) + try container.encode(self.city, forKey: .city) + try container.encode(self.state, forKey: .state) + try container.encode(self.postcode, forKey: .postcode) + try container.encode(self.country, forKey: .country) + try container.encode(self.phone, forKey: .phone) + try container.encode(self.firstName, forKey: .firstName) + try container.encode(self.lastName, forKey: .lastName) + try container.encode(self.email, forKey: .email) + try container.encode(self.defaultAddress, forKey: .defaultAddress) + try container.encode(self.isVerified, forKey: .isVerified) + } + private enum CodingKeys: String, CodingKey { case id case company diff --git a/Networking/Networking/Remote/WooShippingRemote.swift b/Networking/Networking/Remote/WooShippingRemote.swift index 445119f67fb..71a6190a76e 100644 --- a/Networking/Networking/Remote/WooShippingRemote.swift +++ b/Networking/Networking/Remote/WooShippingRemote.swift @@ -38,6 +38,10 @@ public protocol WooShippingRemoteProtocol { func addressValidation(siteID: Int64, address: ShippingLabelAddress, completion: @escaping (Result) -> Void) + func updateOriginAddress(siteID: Int64, + address: WooShippingOriginAddress, + isVerified: Bool, + completion: @escaping (Result) -> Void) } /// Shipping Labels Remote Endpoints for the WooShipping Plugin. @@ -316,6 +320,34 @@ public final class WooShippingRemote: Remote, WooShippingRemoteProtocol { completion(.failure(error)) } } + + /// Updates an origin address. + /// - Parameters: + /// - siteID: Remote ID of the site. + /// - address: The updated origin address. + /// - isVerified: Whether the address has been remotely verified. + /// - completion: Closure to be executed upon completion. + public func updateOriginAddress(siteID: Int64, + address: WooShippingOriginAddress, + isVerified: Bool, + completion: @escaping (Result) -> Void) { + do { + let parameters: [String: Any] = [ + ParameterKey.address: try address.toDictionary(), + ParameterKey.isVerified: isVerified + ] + let request = JetpackRequest(wooApiVersion: .wooShipping, + method: .post, + siteID: siteID, + path: Path.updateOrigin, + parameters: parameters, + availableAsRESTRequest: true) + let mapper = WooShippingOriginAddressUpdateMapper() + enqueue(request, mapper: mapper, completion: completion) + } catch { + completion(.failure(error)) + } + } } // MARK: Constants @@ -329,6 +361,7 @@ private extension WooShippingRemote { static let print = "label/print" static let originAddresses = "address/origins" static let normalizeAddress = "address/normalize" + static let updateOrigin = "address/update_origin" } enum ParameterKey { @@ -345,6 +378,7 @@ private extension WooShippingRemote { static let paperSize = "paper_size" static let labelIDCSV = "label_id_csv" static let address = "address" + static let isVerified = "isVerified" } } diff --git a/Networking/NetworkingTests/Remote/WooShippingRemoteTests.swift b/Networking/NetworkingTests/Remote/WooShippingRemoteTests.swift index f456df55d87..90f53eca194 100644 --- a/Networking/NetworkingTests/Remote/WooShippingRemoteTests.swift +++ b/Networking/NetworkingTests/Remote/WooShippingRemoteTests.swift @@ -399,19 +399,7 @@ final class WooShippingRemoteTests: XCTestCase { // Then let addresses = try XCTUnwrap(result.get()) XCTAssertEqual(addresses.count, 1) - XCTAssertEqual(addresses.first?.company, "Superlative Centaur") - XCTAssertEqual(addresses.first?.city, "SAN FRANCISCO") - XCTAssertEqual(addresses.first?.state, "CA") - XCTAssertEqual(addresses.first?.postcode, "94110-4929") - XCTAssertEqual(addresses.first?.country, "US") - XCTAssertEqual(addresses.first?.phone, "12345678901") - XCTAssertEqual(addresses.first?.address1, "60 29TH ST PMB 343") - XCTAssertEqual(addresses.first?.firstName, "First") - XCTAssertEqual(addresses.first?.lastName, "Last") - XCTAssertEqual(addresses.first?.email, "email@automattic.com") - XCTAssertEqual(addresses.first?.id, "store_details") - XCTAssertEqual(addresses.first?.defaultAddress, true) - XCTAssertEqual(addresses.first?.isVerified, true) + XCTAssertEqual(addresses.first, sampleOriginAddress()) } func test_loadOriginAddresses_returns_error_on_failure() throws { @@ -488,6 +476,44 @@ final class WooShippingRemoteTests: XCTestCase { // Then XCTAssertNotNil(result.failure) } + + func test_updateOriginAddress_parses_success_response() throws { + // Given + let remote = WooShippingRemote(network: network) + network.simulateResponse(requestUrlSuffix: "address/update_origin", filename: "wooshipping-update-origin-success") + + // When + let result: Result = waitFor { promise in + remote.updateOriginAddress(siteID: self.sampleSiteID, + address: WooShippingOriginAddress.fake(), + isVerified: true) { result in + promise(result) + } + } + + // Then + let addressUpdate = try XCTUnwrap(result.get()) + XCTAssertEqual(addressUpdate.address, sampleOriginAddress()) + XCTAssertTrue(addressUpdate.isVerified) + } + + func test_updateOriginAddress_returns_error_on_network_failure() { + // Given + let remote = WooShippingRemote(network: network) + network.simulateResponse(requestUrlSuffix: "address/update_origin", filename: "generic_error") + + // When + let result: Result = waitFor { promise in + remote.updateOriginAddress(siteID: self.sampleSiteID, + address: WooShippingOriginAddress.fake(), + isVerified: true) { result in + promise(result) + } + } + + // Then + XCTAssertNotNil(result.failure) + } } private extension WooShippingRemoteTests { @@ -514,4 +540,21 @@ private extension WooShippingRemoteTests { dimensions: "12 x 12 x 12", boxWeight: 0.01) } + + func sampleOriginAddress() -> WooShippingOriginAddress { + WooShippingOriginAddress(id: "store_details", + company: "Superlative Centaur", + address1: "60 29TH ST PMB 343", + address2: "", + city: "SAN FRANCISCO", + state: "CA", + postcode: "94110-4929", + country: "US", + phone: "12345678901", + firstName: "First", + lastName: "Last", + email: "email@automattic.com", + defaultAddress: true, + isVerified: true) + } } diff --git a/Yosemite/YosemiteTests/Mocks/Networking/Remote/MockWooShippingRemote.swift b/Yosemite/YosemiteTests/Mocks/Networking/Remote/MockWooShippingRemote.swift index 43f4dcb4d85..c6aa58a1f36 100644 --- a/Yosemite/YosemiteTests/Mocks/Networking/Remote/MockWooShippingRemote.swift +++ b/Yosemite/YosemiteTests/Mocks/Networking/Remote/MockWooShippingRemote.swift @@ -42,6 +42,9 @@ final class MockWooShippingRemote { /// The results to return based on the given arguments in `addressValidation` private var addressValidation = [ResultKey: Result]() + /// The results to return based on the given arguments in `updateOriginAddress` + private var updateOriginAddress = [ResultKey: Result]() + /// Set the value passed to the `completion` block if `createPackage` is called. func whenCreatePackage(siteID: Int64, thenReturn result: Result) { @@ -111,6 +114,13 @@ final class MockWooShippingRemote { let key = ResultKey(siteID: siteID) addressValidation[key] = result } + + /// Set the value passed to the `completion` block if `updateOriginAddress` is called. + func whenupdatingOriginAddress(siteID: Int64, + thenReturn result: Result) { + let key = ResultKey(siteID: siteID) + updateOriginAddress[key] = result + } } // MARK: - WooShippingRemoteProtocol @@ -270,4 +280,20 @@ extension MockWooShippingRemote: WooShippingRemoteProtocol { } } } + + func updateOriginAddress(siteID: Int64, + address: WooShippingOriginAddress, + isVerified: Bool, + completion: @escaping (Result) -> Void) { + DispatchQueue.main.async { [weak self] in + guard let self = self else { return } + + let key = ResultKey(siteID: siteID) + if let result = self.updateOriginAddress[key] { + completion(result) + } else { + XCTFail("\(String(describing: self)) Could not find Result for \(key)") + } + } + } }