Repository: woocommerce/woocommerce-ios
Pull request #15446: [Shipping Labels] Update shipment endpoint - Yosemite layer
Author: login: selanthiraiyan
Labels: name: feature: shipping labels
description: Related to creating, ordering, or printing shipping labels.
Created: 2025-03-28T05:31:14Z | Merged: 2025-03-28T15:36:48Z

<!-- Remember about a good descriptive title. -->

Part of: #15308
<!-- Id number of the GitHub issue this PR addresses. -->
<!-- Part of: # -> use this if your PR is one of many related to one issue -->

<!-- 
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🛠 Need an AI review?  
Add a comment: `@coderabbitai review`
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
-->

## Description
<!-- Take the time to write a good summary. Why is it needed? What does it do? When fixing bugs try to avoid just writing “See original issue” – clarify what the problem was and how you’ve fixed it. -->


Adds support for updating shipments in the Yosemite layer. 

Changes
- New action to update shipments.
- Unit tests.

## Steps to reproduce
<!-- Step-by-step testing instructions. For new user flows, consider instead stating the goal of the workflow and see if your PR reviewer can accomplish the workflow without specific steps! -->
This endpoint isn't used yet. Unit tests should pass. 

## Testing information
<!-- This is your opportunity to break out individual scenarios that need testing (when necessary) and/or include a checklist for the reviewer to go through. Consider documenting the following from your own completed testing: devices used, alternate workflows, edge cases, affected areas, critical flows, areas not tested, and any remaining unknowns. Provide feedback on this new section of the PR template through Sept 30, 2024 to Apps Quality; additional context here: p91TBi-b8z-p2#comment-12036 -->
NA

## Screenshots
<!-- Include before and after images or gifs when appropriate. -->
NA

---
- [x] I have considered if this change warrants user-facing release notes and have added them to `RELEASE-NOTES.txt` if necessary.

## Reviewer (or Author, in the case of optional code reviews):

Please make sure these conditions are met before approving the PR, or request changes if the PR needs improvement:

- [ ] The PR is small and has a clear, single focus, or a valid explanation is provided in the description. If needed, please request to split it into smaller PRs.
- [ ] Ensure Adequate Unit Test Coverage: The changes are reasonably covered by unit tests or an explanation is provided in the PR description.
- [ ] Manual Testing: The author listed all the tests they ran, including smoke tests when needed (e.g., for refactorings). The reviewer confirmed that the PR works as expected on all devices (phone/tablet) and no regressions are added.


Diff:
diff --git a/Fakes/Fakes/Networking.generated.swift b/Fakes/Fakes/Networking.generated.swift
index 33e8dffcc9d..c239f8d31ea 100644
--- a/Fakes/Fakes/Networking.generated.swift
+++ b/Fakes/Fakes/Networking.generated.swift
@@ -2999,10 +2999,10 @@ extension Networking.WooShippingSavedPredefinedPackage {
         )
     }
 }
-extension Networking.WooShippingShipment {
+extension Networking.WooShippingShipmentItem {
     /// Returns a "ready to use" type filled with fake values.
     ///
-    public static func fake() -> Networking.WooShippingShipment {
+    public static func fake() -> Networking.WooShippingShipmentItem {
         .init(
             id: .fake(),
             subItems: .fake()
@@ -3024,8 +3024,6 @@ extension Networking.WooShippingUpdateShipmentResponse {
     ///
     public static func fake() -> Networking.WooShippingUpdateShipmentResponse {
         .init(
-            siteID: .fake(),
-            orderID: .fake(),
             shipments: .fake()
         )
     }
diff --git a/Networking/Networking.xcodeproj/project.pbxproj b/Networking/Networking.xcodeproj/project.pbxproj
index 5ce482e3349..3fe31a23f8f 100644
--- a/Networking/Networking.xcodeproj/project.pbxproj
+++ b/Networking/Networking.xcodeproj/project.pbxproj
@@ -1270,7 +1270,7 @@
 		EE76762F2962B85E000066FA /* RequestProcessorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE76762E2962B85E000066FA /* RequestProcessorTests.swift */; };
 		EE7E80B82D84F19100E6FF5B /* WooShippingConfigMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE7E80B72D84F18700E6FF5B /* WooShippingConfigMapper.swift */; };
 		EE7E80BA2D84F42E00E6FF5B /* WooShippingConfigResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE7E80B92D84F41500E6FF5B /* WooShippingConfigResponse.swift */; };
-		EE7E80BD2D84F55100E6FF5B /* WooShippingShipment.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE7E80BC2D84F54800E6FF5B /* WooShippingShipment.swift */; };
+		EE7E80BD2D84F55100E6FF5B /* WooShippingShipmentItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE7E80BC2D84F54800E6FF5B /* WooShippingShipmentItem.swift */; };
 		EE80A24729547F8B003591E4 /* coupons-all-without-data.json in Resources */ = {isa = PBXBuildFile; fileRef = EE80A24529547F8B003591E4 /* coupons-all-without-data.json */; };
 		EE80A24829547F8B003591E4 /* coupon-without-data.json in Resources */ = {isa = PBXBuildFile; fileRef = EE80A24629547F8B003591E4 /* coupon-without-data.json */; };
 		EE80A25029556FBD003591E4 /* coupon-reports-without-data.json in Resources */ = {isa = PBXBuildFile; fileRef = EE80A24F29556FBD003591E4 /* coupon-reports-without-data.json */; };
@@ -2515,7 +2515,7 @@
 		EE76762E2962B85E000066FA /* RequestProcessorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestProcessorTests.swift; sourceTree = "<group>"; };
 		EE7E80B72D84F18700E6FF5B /* WooShippingConfigMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WooShippingConfigMapper.swift; sourceTree = "<group>"; };
 		EE7E80B92D84F41500E6FF5B /* WooShippingConfigResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WooShippingConfigResponse.swift; sourceTree = "<group>"; };
-		EE7E80BC2D84F54800E6FF5B /* WooShippingShipment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WooShippingShipment.swift; sourceTree = "<group>"; };
+		EE7E80BC2D84F54800E6FF5B /* WooShippingShipmentItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WooShippingShipmentItem.swift; sourceTree = "<group>"; };
 		EE80A24529547F8B003591E4 /* coupons-all-without-data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "coupons-all-without-data.json"; sourceTree = "<group>"; };
 		EE80A24629547F8B003591E4 /* coupon-without-data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "coupon-without-data.json"; sourceTree = "<group>"; };
 		EE80A24F29556FBD003591E4 /* coupon-reports-without-data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "coupon-reports-without-data.json"; sourceTree = "<group>"; };
@@ -4256,7 +4256,7 @@
 			isa = PBXGroup;
 			children = (
 				EEBBDD832D943D25008D6CE5 /* WooShippingUpdateShipment.swift */,
-				EE7E80BC2D84F54800E6FF5B /* WooShippingShipment.swift */,
+				EE7E80BC2D84F54800E6FF5B /* WooShippingShipmentItem.swift */,
 				EE7E80B92D84F41500E6FF5B /* WooShippingConfigResponse.swift */,
 				EEBBDD872D944194008D6CE5 /* WooShippingUpdateShipmentResponse.swift */,
 			);
@@ -5595,7 +5595,7 @@
 				451A97C92609FF050059D135 /* ShippingLabelPackagesResponse.swift in Sources */,
 				029BA4F0255D7282006171FD /* ShippingLabelRemote.swift in Sources */,
 				B557DA0F20975E07005962F4 /* DotcomRequest.swift in Sources */,
-				EE7E80BD2D84F55100E6FF5B /* WooShippingShipment.swift in Sources */,
+				EE7E80BD2D84F55100E6FF5B /* WooShippingShipmentItem.swift in Sources */,
 				AEF94585272974F2001DCCFB /* TelemetryRemote.swift in Sources */,
 				DE20046E2BFB522900660A72 /* ProductReportListMapper.swift in Sources */,
 				740211E321939C84002248DA /* CommentResultMapper.swift in Sources */,
diff --git a/Networking/Networking/Mapper/WooShippingUpdateShipmentMapper.swift b/Networking/Networking/Mapper/WooShippingUpdateShipmentMapper.swift
index 4432037b6ca..a30d3b2f921 100644
--- a/Networking/Networking/Mapper/WooShippingUpdateShipmentMapper.swift
+++ b/Networking/Networking/Mapper/WooShippingUpdateShipmentMapper.swift
@@ -3,30 +3,14 @@ import Foundation
 /// Mapper: Shipping Label Update Shipments Response from WooCommerce Shipping extension
 ///
 struct WooShippingUpdateShipmentMapper: Mapper {
-    /// Site Identifier associated to the order that will be parsed.
+    /// (Attempts) to convert a dictionary into a dictionary of `WooShippingShipment` values.
     ///
-    /// We're injecting this field via `JSONDecoder.userInfo` because SiteID is not returned by the update shipment endpoint.
-    ///
-    let siteID: Int64
-
-    /// Order ID associated to the shipping labels that will be parsed.
-    ///
-    /// We're injecting this field via `JSONDecoder.userInfo` because OrderID is not returned by the update shipment endpoint.
-    ///
-    let orderID: Int64
-
-    /// (Attempts) to convert a dictionary into WooShippingUpdateShipmentResponse.
-    ///
-    func map(response: Data) throws -> WooShippingUpdateShipmentResponse {
+    func map(response: Data) throws -> WooShippingShipments {
         let decoder = JSONDecoder()
-        decoder.userInfo = [
-            .siteID: siteID,
-            .orderID: orderID
-        ]
         if hasDataEnvelope(in: response) {
-            return try decoder.decode(WooShippingUpdateShipmentResponseEnvelope.self, from: response).data
+            return try decoder.decode(WooShippingUpdateShipmentResponseEnvelope.self, from: response).data.shipments
         } else {
-            return try decoder.decode(WooShippingUpdateShipmentResponse.self, from: response)
+            return try decoder.decode(WooShippingUpdateShipmentResponse.self, from: response).shipments
         }
     }
 }
diff --git a/Networking/Networking/Model/Copiable/Models+Copiable.generated.swift b/Networking/Networking/Model/Copiable/Models+Copiable.generated.swift
index dcafb9e752d..da6d596ba02 100644
--- a/Networking/Networking/Model/Copiable/Models+Copiable.generated.swift
+++ b/Networking/Networking/Model/Copiable/Models+Copiable.generated.swift
@@ -4227,7 +4227,7 @@ extension Networking.WooShippingAddress {
 extension Networking.WooShippingConfig {
     public func copy(
         siteID: CopiableProp<Int64> = .copy,
-        shipments: CopiableProp<[String: [WooShippingShipment]]> = .copy,
+        shipments: CopiableProp<WooShippingShipments> = .copy,
         shippingLabelData: NullableCopiableProp<WooShippingLabelData> = .copy
     ) -> Networking.WooShippingConfig {
         let siteID = siteID ?? self.siteID
@@ -4470,15 +4470,15 @@ extension Networking.WooShippingPackagesResponse {
     }
 }
 
-extension Networking.WooShippingShipment {
+extension Networking.WooShippingShipmentItem {
     public func copy(
         id: CopiableProp<Int64> = .copy,
         subItems: NullableCopiableProp<[String]> = .copy
-    ) -> Networking.WooShippingShipment {
+    ) -> Networking.WooShippingShipmentItem {
         let id = id ?? self.id
         let subItems = subItems ?? self.subItems
 
-        return Networking.WooShippingShipment(
+        return Networking.WooShippingShipmentItem(
             id: id,
             subItems: subItems
         )
@@ -4488,7 +4488,7 @@ extension Networking.WooShippingShipment {
 extension Networking.WooShippingUpdateShipment {
     public func copy(
         shipmentIdsToUpdate: CopiableProp<[String]> = .copy,
-        shipments: CopiableProp<[String: [WooShippingShipment]]> = .copy
+        shipments: CopiableProp<WooShippingShipments> = .copy
     ) -> Networking.WooShippingUpdateShipment {
         let shipmentIdsToUpdate = shipmentIdsToUpdate ?? self.shipmentIdsToUpdate
         let shipments = shipments ?? self.shipments
@@ -4502,17 +4502,11 @@ extension Networking.WooShippingUpdateShipment {
 
 extension Networking.WooShippingUpdateShipmentResponse {
     public func copy(
-        siteID: CopiableProp<Int64> = .copy,
-        orderID: CopiableProp<Int64> = .copy,
-        shipments: CopiableProp<[String: [WooShippingShipment]]> = .copy
+        shipments: CopiableProp<WooShippingShipments> = .copy
     ) -> Networking.WooShippingUpdateShipmentResponse {
-        let siteID = siteID ?? self.siteID
-        let orderID = orderID ?? self.orderID
         let shipments = shipments ?? self.shipments
 
         return Networking.WooShippingUpdateShipmentResponse(
-            siteID: siteID,
-            orderID: orderID,
             shipments: shipments
         )
     }
diff --git a/Networking/Networking/Model/ShippingLabel/Shipments/WooShippingConfigResponse.swift b/Networking/Networking/Model/ShippingLabel/Shipments/WooShippingConfigResponse.swift
index 048a8f687a9..d45bd09ed48 100644
--- a/Networking/Networking/Model/ShippingLabel/Shipments/WooShippingConfigResponse.swift
+++ b/Networking/Networking/Model/ShippingLabel/Shipments/WooShippingConfigResponse.swift
@@ -16,13 +16,13 @@ public struct WooShippingConfig: Decodable, Equatable, GeneratedFakeable, Genera
     public let siteID: Int64
 
     /// Shipments of this order. The keys are the ids of the shipment.
-    public let shipments: [String: [WooShippingShipment]]
+    public let shipments: WooShippingShipments
 
     /// Holds info about the shipping labels
     public let shippingLabelData: WooShippingLabelData?
 
     public init(siteID: Int64,
-                shipments: [String: [WooShippingShipment]],
+                shipments: WooShippingShipments,
                 shippingLabelData: WooShippingLabelData?) {
         self.siteID = siteID
         self.shipments = shipments
@@ -40,13 +40,13 @@ public struct WooShippingConfig: Decodable, Equatable, GeneratedFakeable, Genera
         }
 
         let container = try decoder.container(keyedBy: CodingKeys.self)
-        let shipments: [String: [WooShippingShipment]] = {
+        let shipments: WooShippingShipments = {
             guard let shipmentsString = try? container.decodeIfPresent(String.self, forKey: .shipments),
                   let data = shipmentsString.data(using: .utf8) else {
                 return [:]
             }
 
-            return (try? JSONDecoder().decode([String: [WooShippingShipment]].self, from: data)) ?? [:]
+            return (try? JSONDecoder().decode(WooShippingShipments.self, from: data)) ?? [:]
         }()
 
         let shippingLabelData = try container.decodeIfPresent(WooShippingLabelData.self, forKey: .shippingLabelData)
diff --git a/Networking/Networking/Model/ShippingLabel/Shipments/WooShippingShipment.swift b/Networking/Networking/Model/ShippingLabel/Shipments/WooShippingShipmentItem.swift
similarity index 68%
rename from Networking/Networking/Model/ShippingLabel/Shipments/WooShippingShipment.swift
rename to Networking/Networking/Model/ShippingLabel/Shipments/WooShippingShipmentItem.swift
index 4023ae42649..979371562c6 100644
--- a/Networking/Networking/Model/ShippingLabel/Shipments/WooShippingShipment.swift
+++ b/Networking/Networking/Model/ShippingLabel/Shipments/WooShippingShipmentItem.swift
@@ -4,7 +4,7 @@ import WooFoundation
 
 /// Represents a shipment in Shipping Labels for the WooCommerce Shipping extension.
 ///
-public struct WooShippingShipment: Codable, Equatable, GeneratedFakeable, GeneratedCopiable {
+public struct WooShippingShipmentItem: Codable, Equatable, GeneratedFakeable, GeneratedCopiable {
     /// ID of the shipment
     public let id: Int64
 
@@ -16,3 +16,5 @@ public struct WooShippingShipment: Codable, Equatable, GeneratedFakeable, Genera
         self.subItems = subItems
     }
 }
+
+public typealias WooShippingShipments = [String: [WooShippingShipmentItem]]
diff --git a/Networking/Networking/Model/ShippingLabel/Shipments/WooShippingUpdateShipment.swift b/Networking/Networking/Model/ShippingLabel/Shipments/WooShippingUpdateShipment.swift
index 9f8cfe50afb..4bae5c7e69a 100644
--- a/Networking/Networking/Model/ShippingLabel/Shipments/WooShippingUpdateShipment.swift
+++ b/Networking/Networking/Model/ShippingLabel/Shipments/WooShippingUpdateShipment.swift
@@ -6,9 +6,9 @@ import Codegen
 public struct WooShippingUpdateShipment: Equatable, Encodable, GeneratedFakeable, GeneratedCopiable {
     public let shipmentIdsToUpdate: [String]
 
-    public let shipments: [String: [WooShippingShipment]]
+    public let shipments: WooShippingShipments
 
-    public init(shipmentIdsToUpdate: [String], shipments: [String: [WooShippingShipment]]) {
+    public init(shipmentIdsToUpdate: [String], shipments: WooShippingShipments) {
         self.shipmentIdsToUpdate = shipmentIdsToUpdate
         self.shipments = shipments
     }
diff --git a/Networking/Networking/Model/ShippingLabel/Shipments/WooShippingUpdateShipmentResponse.swift b/Networking/Networking/Model/ShippingLabel/Shipments/WooShippingUpdateShipmentResponse.swift
index 141fd924928..fbeac7f4eaf 100644
--- a/Networking/Networking/Model/ShippingLabel/Shipments/WooShippingUpdateShipmentResponse.swift
+++ b/Networking/Networking/Model/ShippingLabel/Shipments/WooShippingUpdateShipmentResponse.swift
@@ -4,15 +4,9 @@ import Codegen
 /// Response after updating shipments of an order
 ///
 public struct WooShippingUpdateShipmentResponse: Decodable, Equatable, GeneratedFakeable, GeneratedCopiable {
-    public let siteID: Int64
-    public let orderID: Int64
-    public let shipments: [String: [WooShippingShipment]]
+    public let shipments: WooShippingShipments
 
-    public init(siteID: Int64,
-                orderID: Int64,
-                shipments: [String: [WooShippingShipment]]) {
-        self.siteID = siteID
-        self.orderID = orderID
+    public init(shipments: WooShippingShipments) {
         self.shipments = shipments
     }
 
@@ -21,33 +15,16 @@ public struct WooShippingUpdateShipmentResponse: Decodable, Equatable, Generated
     }
 
     public init(from decoder: Decoder) throws {
-        guard let siteID = decoder.userInfo[.siteID] as? Int64 else {
-            throw WooShippingUpdateShipmentDecodingError.missingSiteID
-        }
-
-        guard let orderID = decoder.userInfo[.orderID] as? Int64 else {
-            throw WooShippingUpdateShipmentDecodingError.missingOrderID
-        }
-
         let container = try decoder.container(keyedBy: CodingKeys.self)
-        let shipments: [String: [WooShippingShipment]] = {
+        let shipments: WooShippingShipments = {
             guard let shipmentsString = try? container.decodeIfPresent(String.self, forKey: .data),
                   let data = shipmentsString.data(using: .utf8) else {
                 return [:]
             }
 
-            return (try? JSONDecoder().decode([String: [WooShippingShipment]].self, from: data)) ?? [:]
+            return (try? JSONDecoder().decode(WooShippingShipments.self, from: data)) ?? [:]
         }()
 
-        self.init(siteID: siteID,
-                  orderID: orderID,
-                  shipments: shipments)
+        self.init(shipments: shipments)
     }
 }
-
-// MARK: - Decoding Errors
-//
-enum WooShippingUpdateShipmentDecodingError: Error {
-    case missingSiteID
-    case missingOrderID
-}
diff --git a/Networking/Networking/Remote/WooShippingRemote.swift b/Networking/Networking/Remote/WooShippingRemote.swift
index 894cfc5a664..65583880804 100644
--- a/Networking/Networking/Remote/WooShippingRemote.swift
+++ b/Networking/Networking/Remote/WooShippingRemote.swift
@@ -55,7 +55,7 @@ public protocol WooShippingRemoteProtocol {
     func updateShipment(siteID: Int64,
                         orderID: Int64,
                         shipmentToUpdate: WooShippingUpdateShipment,
-                        completion: @escaping (Result<WooShippingUpdateShipmentResponse, Error>) -> Void)
+                        completion: @escaping (Result<WooShippingShipments, Error>) -> Void)
 }
 
 /// Shipping Labels Remote Endpoints for the WooShipping Plugin.
@@ -444,7 +444,7 @@ public final class WooShippingRemote: Remote, WooShippingRemoteProtocol {
     public func updateShipment(siteID: Int64,
                                orderID: Int64,
                                shipmentToUpdate: WooShippingUpdateShipment,
-                               completion: @escaping (Result<WooShippingUpdateShipmentResponse, Error>) -> Void) {
+                               completion: @escaping (Result<WooShippingShipments, Error>) -> Void) {
         do {
             let parameters = try shipmentToUpdate.toDictionary()
             let path = Path.updateShipment(orderID: orderID)
@@ -454,7 +454,7 @@ public final class WooShippingRemote: Remote, WooShippingRemoteProtocol {
                                          path: path,
                                          parameters: parameters,
                                          availableAsRESTRequest: true)
-            let mapper = WooShippingUpdateShipmentMapper(siteID: siteID, orderID: orderID)
+            let mapper = WooShippingUpdateShipmentMapper()
             enqueue(request, mapper: mapper, completion: completion)
         } catch {
             completion(.failure(error))
diff --git a/Networking/NetworkingTests/Mapper/WooShippingUpdateShipmentMapperTests.swift b/Networking/NetworkingTests/Mapper/WooShippingUpdateShipmentMapperTests.swift
index 4a18c286311..357a0a61fd6 100644
--- a/Networking/NetworkingTests/Mapper/WooShippingUpdateShipmentMapperTests.swift
+++ b/Networking/NetworkingTests/Mapper/WooShippingUpdateShipmentMapperTests.swift
@@ -4,17 +4,14 @@ import XCTest
 /// Unit Tests for `WooShippingUpdateShipmentMapper`
 ///
 final class WooShippingUpdateShipmentMapperTests: XCTestCase {
-    private let sampleSiteID: Int64 = 1234
-    private let sampleOrderID: Int64 = 1234
-
     func test_shipments_are_properly_parsed() throws {
-        guard let config = mapLoadShippingLabelConfig() else {
+        guard let shipments = mapLoadShippingLabelConfig() else {
             XCTFail()
             return
         }
 
-        XCTAssertEqual(config.shipments.count, 3)
-        let shipment = try XCTUnwrap(config.shipments["0"])
+        XCTAssertEqual(shipments.count, 3)
+        let shipment = try XCTUnwrap(shipments["0"])
 
         let shipmentItem = try XCTUnwrap(shipment.first)
         XCTAssertEqual(shipmentItem.id, 209)
@@ -22,13 +19,13 @@ final class WooShippingUpdateShipmentMapperTests: XCTestCase {
     }
 
     func test_shipments_are_properly_parsed_when_response_has_no_data_envelope() throws {
-        guard let config = mapLoadShippingLabelConfig() else {
+        guard let shipments = mapLoadShippingLabelConfig() else {
             XCTFail()
             return
         }
 
-        XCTAssertEqual(config.shipments.count, 3)
-        let shipment = try XCTUnwrap(config.shipments["1"])
+        XCTAssertEqual(shipments.count, 3)
+        let shipment = try XCTUnwrap(shipments["1"])
 
         let shipmentItem = try XCTUnwrap(shipment[safe: 2])
         XCTAssertEqual(shipmentItem.id, 212)
@@ -41,24 +38,23 @@ private extension WooShippingUpdateShipmentMapperTests {
 
     /// Returns the `WooShippingUpdateShipmentMapper` output upon receiving `filename` (Data Encoded)
     ///
-    func mapShippingLabelConfig(from filename: String) -> WooShippingUpdateShipmentResponse? {
+    func mapShippingLabelConfig(from filename: String) -> WooShippingShipments? {
         guard let response = Loader.contentsOf(filename) else {
             return nil
         }
 
-        return try! WooShippingUpdateShipmentMapper(siteID: sampleSiteID,
-                                                    orderID: sampleOrderID).map(response: response)
+        return try! WooShippingUpdateShipmentMapper().map(response: response)
     }
 
     /// Returns the `WooShippingUpdateShipmentMapper` output upon receiving `shipping-label-update-shipment`
     ///
-    func mapLoadShippingLabelConfig() -> WooShippingUpdateShipmentResponse? {
+    func mapLoadShippingLabelConfig() -> WooShippingShipments? {
         mapShippingLabelConfig(from: "shipping-label-update-shipment")
     }
 
     /// Returns the `WooShippingUpdateShipmentMapper` output upon receiving `shipping-label-update-shipment-without-data`
     ///
-    func mapLoadShippingLabelConfigWithoutDataEnvelope() -> WooShippingUpdateShipmentResponse? {
+    func mapLoadShippingLabelConfigWithoutDataEnvelope() -> WooShippingShipments? {
         mapShippingLabelConfig(from: "shipping-label-update-shipment-without-data")
     }
 }
diff --git a/Networking/NetworkingTests/Remote/WooShippingRemoteTests.swift b/Networking/NetworkingTests/Remote/WooShippingRemoteTests.swift
index dbfe62e50ab..5759e5d7279 100644
--- a/Networking/NetworkingTests/Remote/WooShippingRemoteTests.swift
+++ b/Networking/NetworkingTests/Remote/WooShippingRemoteTests.swift
@@ -682,7 +682,7 @@ final class WooShippingRemoteTests: XCTestCase {
         network.simulateResponse(requestUrlSuffix: "shipments/\(sampleOrderID)", filename: "shipping-label-update-shipment")
 
         // When
-        let result: Result<WooShippingUpdateShipmentResponse, Error> = waitFor { promise in
+        let result: Result<WooShippingShipments, Error> = waitFor { promise in
             remote.updateShipment(siteID: self.sampleSiteID,
                                   orderID: self.sampleOrderID,
                                   shipmentToUpdate: WooShippingUpdateShipment.fake()) { result in
@@ -691,8 +691,8 @@ final class WooShippingRemoteTests: XCTestCase {
         }
 
         // Then
-        let config = try XCTUnwrap(result.get())
-        XCTAssertEqual(config.shipments.count, 3)
+        let shipments = try XCTUnwrap(result.get())
+        XCTAssertEqual(shipments.count, 3)
     }
 
     func test_updateShipment_returns_error_on_network_failure() {
@@ -701,7 +701,7 @@ final class WooShippingRemoteTests: XCTestCase {
         network.simulateResponse(requestUrlSuffix: "shipments/\(sampleOrderID)", filename: "generic_error")
 
         // When
-        let result: Result<WooShippingUpdateShipmentResponse, Error> = waitFor { promise in
+        let result: Result<WooShippingShipments, Error> = waitFor { promise in
             remote.updateShipment(siteID: self.sampleSiteID,
                                   orderID: self.sampleOrderID,
                                   shipmentToUpdate: WooShippingUpdateShipment.fake()) { result in
diff --git a/WooCommerce/Classes/ViewRelated/Orders/Order Details/Shipping Labels/Create Shipping Label Form/Package Details/ShippingLabelSampleData.swift b/WooCommerce/Classes/ViewRelated/Orders/Order Details/Shipping Labels/Create Shipping Label Form/Package Details/ShippingLabelSampleData.swift
index baaefccf50a..68f625dfbe5 100644
--- a/WooCommerce/Classes/ViewRelated/Orders/Order Details/Shipping Labels/Create Shipping Label Form/Package Details/ShippingLabelSampleData.swift	
+++ b/WooCommerce/Classes/ViewRelated/Orders/Order Details/Shipping Labels/Create Shipping Label Form/Package Details/ShippingLabelSampleData.swift	
@@ -56,7 +56,7 @@ enum ShippingLabelSampleData {
 
     static func sampleWooShippingConfig() -> WooShippingConfig {
         WooShippingConfig(siteID: 123,
-                          shipments: ["0": [sampleWooShippingShipment()]],
+                          shipments: ["0": [sampleWooShippingShipmentItem()]],
                           shippingLabelData: nil)
     }
 }
@@ -64,8 +64,8 @@ enum ShippingLabelSampleData {
 // MARK: Helper methods
 //
 private extension ShippingLabelSampleData {
-    static func sampleWooShippingShipment() -> WooShippingShipment {
-        WooShippingShipment(id: 123, subItems: ["123-sub-0", "123-sub-1"])
+    static func sampleWooShippingShipmentItem() -> WooShippingShipmentItem {
+        WooShippingShipmentItem(id: 123, subItems: ["123-sub-0", "123-sub-1"])
     }
 
     static func sampleAddress() -> Address {
diff --git a/Yosemite/Yosemite/Actions/WooShippingAction.swift b/Yosemite/Yosemite/Actions/WooShippingAction.swift
index 9bfa0553d35..0669584e524 100644
--- a/Yosemite/Yosemite/Actions/WooShippingAction.swift
+++ b/Yosemite/Yosemite/Actions/WooShippingAction.swift
@@ -90,4 +90,11 @@ public enum WooShippingAction: Action {
     case loadConfig(siteID: Int64,
                     orderID: Int64,
                     completion: (Result<WooShippingConfig, Error>) -> Void)
+
+    /// Updates shipments for given order
+    ///
+    case updateShipment(siteID: Int64,
+                        orderID: Int64,
+                        shipmentToUpdate: WooShippingUpdateShipment,
+                        completion: (Result<WooShippingShipments, Error>) -> Void)
 }
diff --git a/Yosemite/Yosemite/Model/Model.swift b/Yosemite/Yosemite/Model/Model.swift
index 3cdab3caf81..0883e49a559 100644
--- a/Yosemite/Yosemite/Model/Model.swift
+++ b/Yosemite/Yosemite/Model/Model.swift
@@ -201,7 +201,9 @@ public typealias WooShippingVerifyDestinationAddressSuccess = Networking.WooShip
 public typealias WooShippingDestinationAddress = Networking.WooShippingDestinationAddress
 public typealias WooShippingDestinationAddressUpdate = Networking.WooShippingDestinationAddressUpdate
 public typealias WooShippingConfig = Networking.WooShippingConfig
-public typealias WooShippingShipment = Networking.WooShippingShipment
+public typealias WooShippingUpdateShipment = Networking.WooShippingUpdateShipment
+public typealias WooShippingShipmentItem = Networking.WooShippingShipmentItem
+public typealias WooShippingShipments = Networking.WooShippingShipments
 public typealias WPComPlan = Networking.WPComPlan
 public typealias WPComSitePlan = Networking.WPComSitePlan
 public typealias LoadSiteCurrentPlanError = Networking.LoadSiteCurrentPlanError
diff --git a/Yosemite/Yosemite/Stores/WooShippingStore.swift b/Yosemite/Yosemite/Stores/WooShippingStore.swift
index ccef107862a..fcd95d444e8 100644
--- a/Yosemite/Yosemite/Stores/WooShippingStore.swift
+++ b/Yosemite/Yosemite/Stores/WooShippingStore.swift
@@ -77,6 +77,11 @@ public final class WooShippingStore: Store {
             updateDestinationAddress(siteID: siteID, orderID: orderID, address: address, completion: completion)
         case let .loadConfig(siteID, orderID, completion):
             loadConfig(siteID: siteID, orderID: orderID, completion: completion)
+        case let .updateShipment(siteID, orderID, shipmentToUpdate, completion):
+            updateShipment(siteID: siteID,
+                           orderID: orderID,
+                           shipmentToUpdate: shipmentToUpdate,
+                           completion: completion)
         }
     }
 }
@@ -294,6 +299,13 @@ private extension WooShippingStore {
                     completion: @escaping (Result<WooShippingConfig, Error>) -> Void) {
         remote.loadConfig(siteID: siteID, orderID: orderID, completion: completion)
     }
+
+    func updateShipment(siteID: Int64,
+                        orderID: Int64,
+                        shipmentToUpdate: WooShippingUpdateShipment,
+                        completion: @escaping (Result<WooShippingShipments, Error>) -> Void) {
+        remote.updateShipment(siteID: siteID, orderID: orderID, shipmentToUpdate: shipmentToUpdate, completion: completion)
+    }
 }
 
 // MARK: - Storage
diff --git a/Yosemite/YosemiteTests/Mocks/Networking/Remote/MockWooShippingRemote.swift b/Yosemite/YosemiteTests/Mocks/Networking/Remote/MockWooShippingRemote.swift
index 962545ce9d3..ddb20299fff 100644
--- a/Yosemite/YosemiteTests/Mocks/Networking/Remote/MockWooShippingRemote.swift
+++ b/Yosemite/YosemiteTests/Mocks/Networking/Remote/MockWooShippingRemote.swift
@@ -55,7 +55,7 @@ final class MockWooShippingRemote {
     private var loadConfig = [ResultKey: Result<WooShippingConfig, Error>]()
 
     /// The results to return based on the given arguments in `updateShipment`
-    private var updateShipment = [ResultKey: Result<WooShippingUpdateShipmentResponse, Error>]()
+    private var updateShipment = [ResultKey: Result<WooShippingShipments, Error>]()
 
     /// Set the value passed to the `completion` block if `createPackage` is called.
     func whenCreatePackage(siteID: Int64,
@@ -157,7 +157,7 @@ final class MockWooShippingRemote {
 
     /// Set the value passed to the `completion` block if `updateShipment` is called.
     func whenUpdatingShipment(siteID: Int64,
-                              thenReturn result: Result<WooShippingUpdateShipmentResponse, Error>) {
+                              thenReturn result: Result<WooShippingShipments, Error>) {
         let key = ResultKey(siteID: siteID)
         updateShipment[key] = result
     }
@@ -386,7 +386,7 @@ extension MockWooShippingRemote: WooShippingRemoteProtocol {
     func updateShipment(siteID: Int64,
                         orderID: Int64,
                         shipmentToUpdate: WooShippingUpdateShipment,
-                        completion: @escaping (Result<WooShippingUpdateShipmentResponse, any Error>) -> Void) {
+                        completion: @escaping (Result<WooShippingShipments, any Error>) -> Void) {
         DispatchQueue.main.async { [weak self] in
             guard let self = self else { return }
 
diff --git a/Yosemite/YosemiteTests/Stores/WooShippingStoreTests.swift b/Yosemite/YosemiteTests/Stores/WooShippingStoreTests.swift
index ec5f17ecdfe..c33a312acff 100644
--- a/Yosemite/YosemiteTests/Stores/WooShippingStoreTests.swift
+++ b/Yosemite/YosemiteTests/Stores/WooShippingStoreTests.swift
@@ -576,8 +576,8 @@ final class WooShippingStoreTests: XCTestCase {
         // When
         let printData: ShippingLabelPrintData = waitFor { promise in
             let action = WooShippingAction.printLabel(siteID: self.sampleSiteID,
-                                                     labelIDs: [123],
-                                                     paperSize: .letter) { result in
+                                                      labelIDs: [123],
+                                                      paperSize: .letter) { result in
                 guard let printData = try? result.get() else {
                     XCTFail("Error printing shipping label: \(String(describing: result.failure))")
                     return
@@ -854,7 +854,7 @@ final class WooShippingStoreTests: XCTestCase {
     func test_loadConfig_returns_success_response() throws {
         // Given
         let remote = MockWooShippingRemote()
-        let expectedConfig = WooShippingConfig.fake().copy(shipments: ["0": [WooShippingShipment.fake()]])
+        let expectedConfig = WooShippingConfig.fake().copy(shipments: ["0": [WooShippingShipmentItem.fake()]])
         remote.whenLoadingConfig(siteID: sampleSiteID, thenReturn: .success(expectedConfig))
         let store = WooShippingStore(dispatcher: dispatcher, storageManager: storageManager, network: network, remote: remote)
 
@@ -892,14 +892,61 @@ final class WooShippingStoreTests: XCTestCase {
         let error = try XCTUnwrap(result.failure)
         XCTAssertEqual(error as? NetworkError, expectedError)
     }
+
+
+    // MARK: `updateShipment`
+
+    func test_updateShipment_returns_success_response() throws {
+        // Given
+        let remote = MockWooShippingRemote()
+        let expected = ["0": [WooShippingShipmentItem.fake()]]
+        remote.whenUpdatingShipment(siteID: sampleSiteID, thenReturn: .success(expected))
+        let store = WooShippingStore(dispatcher: dispatcher, storageManager: storageManager, network: network, remote: remote)
+
+        // When
+        let result: Result<WooShippingShipments, Error> = waitFor { promise in
+            let action = WooShippingAction.updateShipment(siteID: self.sampleSiteID,
+                                                          orderID: self.sampleOrderID,
+                                                          shipmentToUpdate: WooShippingUpdateShipment.fake()) { result in
+                promise(result)
+            }
+            store.onAction(action)
+        }
+
+        // Then
+        let actual = try XCTUnwrap(result.get())
+        XCTAssertEqual(actual, expected)
+    }
+
+    func test_updateShipment_returns_error_on_failure() throws {
+        // Given
+        let remote = MockWooShippingRemote()
+        let expectedError = NetworkError.timeout()
+        remote.whenUpdatingShipment(siteID: sampleSiteID, thenReturn: .failure(expectedError))
+        let store = WooShippingStore(dispatcher: dispatcher, storageManager: storageManager, network: network, remote: remote)
+
+        // When
+        let result: Result<WooShippingShipments, Error> = waitFor { promise in
+            let action = WooShippingAction.updateShipment(siteID: self.sampleSiteID,
+                                                          orderID: self.sampleOrderID,
+                                                          shipmentToUpdate: WooShippingUpdateShipment.fake()) { result in
+                promise(result)
+            }
+            store.onAction(action)
+        }
+
+        // Then
+        let error = try XCTUnwrap(result.failure)
+        XCTAssertEqual(error as? NetworkError, expectedError)
+    }
 }
 
 private extension WooShippingStoreTests {
     func sampleLabelRates() -> [ShippingLabelCarriersAndRates] {
         return [ShippingLabelCarriersAndRates(packageID: "123",
-                                             defaultRates: [sampleLabelRate()],
-                                             signatureRequired: [],
-                                             adultSignatureRequired: [])]
+                                              defaultRates: [sampleLabelRate()],
+                                              signatureRequired: [],
+                                              adultSignatureRequired: [])]
     }
 
     func sampleLabelRate() -> ShippingLabelCarrierRate {


Reviews:
user: login: itsmeichigo
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-28T08:27:11Z
user: login: selanthiraiyan
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-28T09:28:29Z
user: login: itsmeichigo
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-28T09:41:56Z
user: login: selanthiraiyan
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-28T11:52:11Z
user: login: itsmeichigo
body: Thank you for the updates, Sharma! :shipit: 
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-28T13:25:12Z

Review comments:
diff_hunk: @@ -90,4 +90,11 @@ public enum WooShippingAction: Action {
     case loadConfig(siteID: Int64,
                     orderID: Int64,
                     completion: (Result<WooShippingConfig, Error>) -> Void)
+
+    /// Updates shipments for given order
+    ///
+    case updateShipment(siteID: Int64,
+                        orderID: Int64,
+                        shipmentToUpdate: WooShippingUpdateShipment,
+                        completion: (Result<WooShippingUpdateShipmentResponse, Error>) -> Void)
path: Yosemite/Yosemite/Actions/WooShippingAction.swift
user: login: itsmeichigo
body: ❓ Could you please share why it's necessary to return the response instead of just the list of shipments?
created_at: 2025-03-28T08:26:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -90,4 +90,11 @@ public enum WooShippingAction: Action {
     case loadConfig(siteID: Int64,
                     orderID: Int64,
                     completion: (Result<WooShippingConfig, Error>) -> Void)
+
+    /// Updates shipments for given order
+    ///
+    case updateShipment(siteID: Int64,
+                        orderID: Int64,
+                        shipmentToUpdate: WooShippingUpdateShipment,
+                        completion: (Result<WooShippingUpdateShipmentResponse, Error>) -> Void)
path: Yosemite/Yosemite/Actions/WooShippingAction.swift
user: login: selanthiraiyan
body: Good question, Huong! I returned `WooShippingUpdateShipmentResponse` as it looked neater than sending back a Dictionary. 

I started sending a `[String: [WooShippingShipment]]` Dictionary in https://github.com/woocommerce/woocommerce-ios/pull/15446/commits/27a57c69857703b210edd3eb5bbfd384d1a95123. 
created_at: 2025-03-28T09:28:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -90,4 +90,11 @@ public enum WooShippingAction: Action {
     case loadConfig(siteID: Int64,
                     orderID: Int64,
                     completion: (Result<WooShippingConfig, Error>) -> Void)
+
+    /// Updates shipments for given order
+    ///
+    case updateShipment(siteID: Int64,
+                        orderID: Int64,
+                        shipmentToUpdate: WooShippingUpdateShipment,
+                        completion: (Result<WooShippingUpdateShipmentResponse, Error>) -> Void)
path: Yosemite/Yosemite/Actions/WooShippingAction.swift
user: login: itsmeichigo
body: Thank you @selanthiraiyan!

From what I understand `[String: [WooShippingShipment]]` means a list of shipments with IDs and the contents. Using `WooShippingShipment` as the contents seems confusing to me.

Should the contents be named `WooShippingShipmentItem` instead? And can we create a new typealias for `WooShippingShipments` to use instead of this dictionary?
created_at: 2025-03-28T09:41:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -90,4 +90,11 @@ public enum WooShippingAction: Action {
     case loadConfig(siteID: Int64,
                     orderID: Int64,
                     completion: (Result<WooShippingConfig, Error>) -> Void)
+
+    /// Updates shipments for given order
+    ///
+    case updateShipment(siteID: Int64,
+                        orderID: Int64,
+                        shipmentToUpdate: WooShippingUpdateShipment,
+                        completion: (Result<WooShippingUpdateShipmentResponse, Error>) -> Void)
path: Yosemite/Yosemite/Actions/WooShippingAction.swift
user: login: selanthiraiyan
body: Great suggestion, Huong! Renaming makes complete sense. Done in https://github.com/woocommerce/woocommerce-ios/pull/15446/commits/83ca647bce98b6f9d957e903d8453ce80ea4447c
created_at: 2025-03-28T11:52:11Z
author_association: CONTRIBUTOR

PR comments:
user: login: wpmobilebot
created_at: 2025-03-28T05:41:09Z
body: <!-- REUSE_ID: prototype-build-link -->

<p><img align='top' src='https://raw.githubusercontent.com/buildkite/emojis/main/img-buildkite-64/firebase.png' width='20px' alt='App Icon' />📲 You can test the changes from this Pull Request in <b>WooCommerce iOS Prototype</b> by scanning the QR code below to install the corresponding build.</p>
<table>
<tr>
  <td rowspan='6' width='260px'><img src='https://api.qrserver.com/v1/create-qr-code/?size=500x500&qzone=4&data=https%3A%2F%2Fappdistribution.firebase.google.com%2Ftesterapps%2F1%3A124902176124%3Aios%3A02259de1e7c42b291620f9%2Freleases%2F0kfishilanq38%3Futm_source%3Dfastlane' width='250' height='250' /></td>
  <td><b>App Name</b></td><td>WooCommerce iOS Prototype</td>
</tr>
<tr><td><b>Build Number</b></td><td><code>29057</code></td></tr>
<tr><td><b>Version</b></td><td><code>PR #15446</code></td></tr>
<tr><td><b>Bundle ID</b></td><td><code>com.automattic.alpha.woocommerce</code></td></tr>
<tr><td><b>Commit</b></td><td>530bf473e53bc67a5ca0c3e4ad807e341cb43a1e</td></tr>
<tr><td><b>Installation URL</b></td><td><a href='https://appdistribution.firebase.google.com/testerapps/1:124902176124:ios:02259de1e7c42b291620f9/releases/0kfishilanq38?utm_source=fastlane'>0kfishilanq38</a></td></tr>
</table>
<em>Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.</em>

author_association: COLLABORATOR