Skip to content

Commit 892858e

Browse files
authored
Merge pull request #9846 from woocommerce/issue/9837-product-decoding-fallbacks
[Reliability] Add fallbacks for known Product decoding errors
2 parents aadb52f + 87a9b00 commit 892858e

File tree

6 files changed

+52
-9
lines changed

6 files changed

+52
-9
lines changed

Networking/Networking/Model/Product/Product.swift

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,12 @@ public struct Product: Codable, GeneratedCopiable, Equatable, GeneratedFakeable
357357

358358
let fullDescription = try container.decodeIfPresent(String.self, forKey: .fullDescription)
359359
let shortDescription = try container.decodeIfPresent(String.self, forKey: .shortDescription)
360-
let sku = try container.decodeIfPresent(String.self, forKey: .sku)
360+
361+
// Even though a plain install of WooCommerce Core provides String values,
362+
// some plugins alter the field value from String to Int or Decimal.
363+
let sku = container.failsafeDecodeIfPresent(targetType: String.self,
364+
forKey: .sku,
365+
alternativeTypes: [.decimal(transform: { NSDecimalNumber(decimal: $0).stringValue })])
361366

362367
// Even though a plain install of WooCommerce Core provides string values,
363368
// some plugins alter the field value from String to Int or Decimal.
@@ -424,7 +429,12 @@ public struct Product: Codable, GeneratedCopiable, Equatable, GeneratedFakeable
424429
let backordered = try container.decode(Bool.self, forKey: .backordered)
425430

426431
let soldIndividually = try container.decodeIfPresent(Bool.self, forKey: .soldIndividually) ?? false
427-
let weight = try container.decodeIfPresent(String.self, forKey: .weight)
432+
433+
// Even though a plain install of WooCommerce Core provides String values,
434+
// some plugins alter the field value from String to Int or Decimal.
435+
let weight = container.failsafeDecodeIfPresent(targetType: String.self,
436+
forKey: .weight,
437+
alternativeTypes: [.decimal(transform: { NSDecimalNumber(decimal: $0).stringValue })])
428438
let dimensions = try container.decode(ProductDimensions.self, forKey: .dimensions)
429439

430440
let shippingRequired = try container.decode(Bool.self, forKey: .shippingRequired)

Networking/Networking/Model/Product/ProductDimensions.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,24 @@ public struct ProductDimensions: Codable, Equatable, GeneratedFakeable {
1717
self.width = width
1818
self.height = height
1919
}
20+
21+
public init(from decoder: Decoder) throws {
22+
let container = try decoder.container(keyedBy: CodingKeys.self)
23+
24+
// Even though a plain install of WooCommerce Core provides String dimension values,
25+
// some plugins may alter the field values from String to Int or Decimal.
26+
let length = container.failsafeDecodeIfPresent(targetType: String.self,
27+
forKey: .length,
28+
alternativeTypes: [.decimal(transform: { NSDecimalNumber(decimal: $0).stringValue })]) ?? ""
29+
let width = container.failsafeDecodeIfPresent(targetType: String.self,
30+
forKey: .width,
31+
alternativeTypes: [.decimal(transform: { NSDecimalNumber(decimal: $0).stringValue })]) ?? ""
32+
let height = container.failsafeDecodeIfPresent(targetType: String.self,
33+
forKey: .height,
34+
alternativeTypes: [.decimal(transform: { NSDecimalNumber(decimal: $0).stringValue })]) ?? ""
35+
36+
self.init(length: length, width: width, height: height)
37+
}
2038
}
2139

2240
/// Defines all of the Dimensions CodingKeys

Networking/Networking/Model/Product/ProductDownload.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ public struct ProductDownload: Codable, Equatable, GeneratedFakeable {
2323
public init(from decoder: Decoder) throws {
2424
let container = try decoder.container(keyedBy: CodingKeys.self)
2525

26-
let downloadID = try container.decode(String.self, forKey: .downloadID)
26+
// Even though a plain install of WooCommerce Core provides String values,
27+
// some plugins alter the field value from String to Int or Decimal.
28+
let downloadID = container.failsafeDecodeIfPresent(targetType: String.self,
29+
forKey: .downloadID,
30+
alternativeTypes: [.decimal(transform: { NSDecimalNumber(decimal: $0).stringValue })]) ?? "0"
2731
let name = try container.decodeIfPresent(String.self, forKey: .name)
2832
let fileURL = try container.decodeIfPresent(String.self, forKey: .fileURL)
2933

Networking/NetworkingTests/Mapper/ProductMapperTests.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,12 @@ final class ProductMapperTests: XCTestCase {
117117
XCTAssertFalse(product.soldIndividually)
118118
XCTAssertTrue(product.purchasable)
119119
XCTAssertEqual(product.permalink, "")
120+
XCTAssertEqual(product.sku, "123")
121+
XCTAssertEqual(product.weight, "213")
122+
XCTAssertEqual(product.dimensions.length, "12")
123+
XCTAssertEqual(product.dimensions.width, "33")
124+
XCTAssertEqual(product.dimensions.height, "54")
125+
XCTAssertEqual(product.downloads.first?.downloadID, "12345")
120126
}
121127

122128
/// Verifies that the `salePrice` field of the Product are parsed correctly when the product is on sale, and the sale price is an empty string

Networking/NetworkingTests/Responses/product-alternative-types.json

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"catalog_visibility": "visible",
1515
"description": "<p>This is the party room!</p>\n",
1616
"short_description": "[contact-form]\n<p>The green room&#8217;s max capacity is 30 people. Reserving the date / time of your event is free. We can also accommodate large groups, with seating for 85 board game players at a time. If you have a large group, let us know and we&#8217;ll send you our large group rate.</p>\n<p>GROUP RATES</p>\n<p>Reserve your event for up to 30 guests for $100.</p>\n",
17-
"sku": "",
17+
"sku": 123,
1818
"price": 17,
1919
"regular_price": 12.89,
2020
"sale_price": 26.73,
@@ -28,7 +28,11 @@
2828
"total_sales": 0,
2929
"virtual": true,
3030
"downloadable": false,
31-
"downloads": [],
31+
"downloads": [{
32+
"id" : 12345,
33+
"name" : "Song #1",
34+
"file" : "https://example.com/woo-single-1.ogg"
35+
}],
3236
"download_limit": -1,
3337
"download_expiry": -1,
3438
"external_url": "http://somewhere.com",
@@ -42,11 +46,11 @@
4246
"backorders_allowed": false,
4347
"backordered": false,
4448
"sold_individually": null,
45-
"weight": "213",
49+
"weight": 213,
4650
"dimensions": {
47-
"length": "12",
48-
"width": "33",
49-
"height": "54"
51+
"length": 12,
52+
"width": 33,
53+
"height": 54
5054
},
5155
"shipping_required": false,
5256
"shipping_taxable": false,

RELEASE-NOTES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
-----
55
- [*] Orders: Allow alternative types for the `taxID` in `ShippingLineTax` or `sku` in `OrderItem`, as some third-party plugins alter the type in the API. This helps with the order list not loading due to order decoding errors. [https://github.com/woocommerce/woocommerce-ios/pull/9844]
66
- [*] Payments: Location permissions request is not shown to TTP users who grant "Allow once" permission on first foregrounding the app any more [https://github.com/woocommerce/woocommerce-ios/pull/9821]
7+
- [*] Products: Allow alternative types for the `sku` and `weight` in `Product`, the dimensions in `ProductDimensions`, and the `downloadID` in `ProductDownload`, as some third-party plugins alter the types in the API. This helps with the product list not loading due to product decoding errors. [https://github.com/woocommerce/woocommerce-ios/pull/9846]
78

89
13.8
910
-----

0 commit comments

Comments
 (0)