Skip to content

Commit ad10bf7

Browse files
authored
[Woo POS][Historical Orders] Order Details - Load product images (#16073)
2 parents db48e93 + 4a438c6 commit ad10bf7

File tree

25 files changed

+248
-39
lines changed

25 files changed

+248
-39
lines changed

Modules/Sources/Fakes/NetworkingCore.generated.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ extension NetworkingCore.OrderItem {
270270
totalTax: .fake(),
271271
attributes: .fake(),
272272
addOns: .fake(),
273+
image: .fake(),
273274
parent: .fake(),
274275
bundleConfiguration: .fake()
275276
)

Modules/Sources/Networking/Model/Copiable/Models+Copiable.generated.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Codegen
55
import Foundation
66
import WooFoundation
77
import struct Alamofire.JSONEncoding
8+
import struct NetworkingCore.JetpackSite
89

910

1011
extension Networking.AIProduct {

Modules/Sources/NetworkingCore/Model/Copiable/Models+Copiable.generated.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,7 @@ extension NetworkingCore.OrderItem {
444444
totalTax: CopiableProp<String> = .copy,
445445
attributes: CopiableProp<[OrderItemAttribute]> = .copy,
446446
addOns: CopiableProp<[OrderItemProductAddOn]> = .copy,
447+
image: NullableCopiableProp<OrderItemProductImage> = .copy,
447448
parent: NullableCopiableProp<Int64> = .copy,
448449
bundleConfiguration: CopiableProp<[OrderItemBundleItem]> = .copy
449450
) -> NetworkingCore.OrderItem {
@@ -462,6 +463,7 @@ extension NetworkingCore.OrderItem {
462463
let totalTax = totalTax ?? self.totalTax
463464
let attributes = attributes ?? self.attributes
464465
let addOns = addOns ?? self.addOns
466+
let image = image ?? self.image
465467
let parent = parent ?? self.parent
466468
let bundleConfiguration = bundleConfiguration ?? self.bundleConfiguration
467469

@@ -481,6 +483,7 @@ extension NetworkingCore.OrderItem {
481483
totalTax: totalTax,
482484
attributes: attributes,
483485
addOns: addOns,
486+
image: image,
484487
parent: parent,
485488
bundleConfiguration: bundleConfiguration
486489
)

Modules/Sources/NetworkingCore/Model/OrderItem.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ public struct OrderItem: Codable, Equatable, Hashable, Sendable, GeneratedFakeab
3030

3131
public let addOns: [OrderItemProductAddOn]
3232

33+
public let image: OrderItemProductImage?
34+
3335
/// Item ID of parent `OrderItem`, if any.
3436
///
3537
/// An `OrderItem` can have a parent if, for example, it is a bundled item within a product bundle.
@@ -58,6 +60,7 @@ public struct OrderItem: Codable, Equatable, Hashable, Sendable, GeneratedFakeab
5860
totalTax: String,
5961
attributes: [OrderItemAttribute],
6062
addOns: [OrderItemProductAddOn],
63+
image: OrderItemProductImage?,
6164
parent: Int64?,
6265
bundleConfiguration: [OrderItemBundleItem]) {
6366
self.itemID = itemID
@@ -75,6 +78,7 @@ public struct OrderItem: Codable, Equatable, Hashable, Sendable, GeneratedFakeab
7578
self.totalTax = totalTax
7679
self.attributes = attributes
7780
self.addOns = addOns
81+
self.image = image
7882
self.parent = parent
7983
self.bundleConfiguration = bundleConfiguration
8084
}
@@ -123,6 +127,9 @@ public struct OrderItem: Codable, Equatable, Hashable, Sendable, GeneratedFakeab
123127
forKey: .attributes)
124128
.first(where: { $0.key == "_pao_ids" })?.value ?? []
125129

130+
// Order item product image
131+
let image = try container.decodeIfPresent(OrderItemProductImage.self, forKey: .image)
132+
126133
// Product Bundle extension properties:
127134
// If the order item is part of a product bundle, `bundledBy` is the parent order item (product bundle).
128135
// If it's not a bundled item, the API returns an empty string for `bundledBy` and the value will be `nil`.
@@ -149,6 +156,7 @@ public struct OrderItem: Codable, Equatable, Hashable, Sendable, GeneratedFakeab
149156
totalTax: totalTax,
150157
attributes: attributes,
151158
addOns: productAddOns,
159+
image: image,
152160
parent: bundledBy ?? compositeParent,
153161
bundleConfiguration: [])
154162
}
@@ -174,6 +182,10 @@ public struct OrderItem: Codable, Equatable, Hashable, Sendable, GeneratedFakeab
174182
try container.encode(total, forKey: .total)
175183
}
176184

185+
if let image = image {
186+
try container.encode(image, forKey: .image)
187+
}
188+
177189
if !bundleConfiguration.isEmpty {
178190
try container.encode(bundleConfiguration, forKey: .bundleConfiguration)
179191
}
@@ -204,6 +216,7 @@ extension OrderItem {
204216
case bundledBy = "bundled_by"
205217
case compositeParent = "composite_parent"
206218
case bundleConfiguration = "bundle_configuration"
219+
case image
207220
}
208221
}
209222

@@ -222,3 +235,24 @@ private struct OrderItemProductAddOnContainer: Decodable {
222235
let key: String
223236
let value: [OrderItemProductAddOn]
224237
}
238+
239+
240+
// MARK: - Order Item Product Image
241+
//
242+
public struct OrderItemProductImage: Codable, Equatable, Hashable, Sendable {
243+
public let src: String?
244+
245+
public init(from decoder: Decoder) throws {
246+
let container = try decoder.container(keyedBy: CodingKeys.self)
247+
self.src = try? container.decodeIfPresent(String.self, forKey: .src)
248+
}
249+
250+
public func encode(to encoder: Encoder) throws {
251+
var container = encoder.container(keyedBy: CodingKeys.self)
252+
try container.encodeIfPresent(src, forKey: .src)
253+
}
254+
255+
private enum CodingKeys: String, CodingKey {
256+
case src
257+
}
258+
}

Modules/Sources/Yosemite/Model/Mocks/MockObjectGraph.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ extension MockObjectGraph {
222222
totalTax: "0",
223223
attributes: [],
224224
addOns: [],
225+
image: nil,
225226
parent: nil,
226227
bundleConfiguration: []
227228
)

Modules/Sources/Yosemite/Model/Storage/OrderItem+ReadOnlyConvertible.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ extension Storage.OrderItem: ReadOnlyConvertible {
5555
totalTax: totalTax ?? "",
5656
attributes: attributes,
5757
addOns: addOns,
58+
image: nil,
5859
parent: parent?.int64Value,
5960
bundleConfiguration: [])
6061
}

Modules/Sources/Yosemite/PointOfSale/OrderList/POSOrderItem.swift

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,25 @@ import Foundation
33
public struct POSOrderItem: Equatable, Hashable {
44
public let itemID: Int64
55
public let name: String
6-
// periphery:ignore - Will be used for images
7-
public let productID: Int64
8-
// periphery:ignore - Will be used for images
9-
public let variationID: Int64
106
public let quantity: Decimal
117
public let formattedPrice: String
128
public let formattedTotal: String
9+
public let imageSrc: String?
1310
public let attributes: [OrderItemAttribute]
1411

1512
public init(itemID: Int64,
1613
name: String,
17-
productID: Int64,
18-
variationID: Int64,
1914
quantity: Decimal,
2015
formattedPrice: String,
2116
formattedTotal: String,
17+
imageSrc: String?,
2218
attributes: [OrderItemAttribute]) {
2319
self.itemID = itemID
2420
self.name = name
25-
self.productID = productID
26-
self.variationID = variationID
2721
self.quantity = quantity
2822
self.formattedPrice = formattedPrice
2923
self.formattedTotal = formattedTotal
24+
self.imageSrc = imageSrc
3025
self.attributes = attributes
3126
}
3227
}

Modules/Sources/Yosemite/PointOfSale/OrderList/POSOrderMapper.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,10 @@ struct POSOrderMapper {
5656
return POSOrderItem(
5757
itemID: orderItem.itemID,
5858
name: orderItem.name,
59-
productID: orderItem.productID,
60-
variationID: orderItem.variationID,
6159
quantity: orderItem.quantity,
6260
formattedPrice: currencyFormatter.formatAmount(orderItem.price, with: currency) ?? "",
6361
formattedTotal: currencyFormatter.formatAmount(orderItem.total, with: currency) ?? "",
62+
imageSrc: orderItem.image?.src,
6463
attributes: orderItem.attributes
6564
)
6665
}

Modules/Sources/Yosemite/Stores/Order/ProductInputTransformer.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ private extension ProductInputTransformer {
241241
totalTax: "",
242242
attributes: [],
243243
addOns: [],
244+
image: nil,
244245
parent: nil,
245246
bundleConfiguration: input.bundleConfiguration.map {
246247
switch $0.productOrVariation {

Modules/Tests/NetworkingTests/Mapper/OrderListMapperTests.swift

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,35 @@ class OrderListMapperTests: XCTestCase {
163163
}
164164
}
165165
}
166-
}
167166

167+
/// Verifies that OrderItem decoding is robust for various image field scenarios from WooCommerce API
168+
///
169+
func test_order_item_image_decoding_robustness() {
170+
let orders = mapOrders(from: "order-item-image")
171+
XCTAssertEqual(orders.count, 1)
172+
173+
let order = orders[0]
174+
XCTAssertEqual(order.items.count, 4)
175+
176+
// Item 1: Product with valid image src
177+
let item1 = order.items[0]
178+
XCTAssertNotNil(item1.image)
179+
XCTAssertEqual(item1.image?.src, "https://example.com/image.jpg")
180+
181+
// Item 2: Product with no image field
182+
let item2 = order.items[1]
183+
XCTAssertNil(item2.image)
184+
185+
// Item 3: Product with image but no src field
186+
let item3 = order.items[2]
187+
XCTAssertNotNil(item3.image)
188+
XCTAssertNil(item3.image?.src)
189+
190+
// Item 4: Product with wrong src type
191+
let item4 = order.items[3]
192+
XCTAssertNil(item4.image?.src)
193+
}
194+
}
168195

169196
/// Private Methods.
170197
///

0 commit comments

Comments
 (0)