Skip to content

Commit aadb52f

Browse files
authored
Merge pull request #9844 from woocommerce/issue/9836-order-decoding-fallbacks
[Reliability] Add fallbacks for known Order decoding errors
2 parents 68bbc4c + 4c849a5 commit aadb52f

File tree

6 files changed

+250
-1
lines changed

6 files changed

+250
-1
lines changed

Networking/Networking.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,7 @@
641641
CE19CB11222486A600E8AF7A /* order-statuses.json in Resources */ = {isa = PBXBuildFile; fileRef = CE19CB10222486A500E8AF7A /* order-statuses.json */; };
642642
CE20179320E3EFA7005B4C18 /* broken-orders.json in Resources */ = {isa = PBXBuildFile; fileRef = CE20179220E3EFA7005B4C18 /* broken-orders.json */; };
643643
CE227093228DD44C00C0626C /* ProductStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE227092228DD44C00C0626C /* ProductStatus.swift */; };
644+
CE2678432A26102A00FD9AEB /* order-alternative-types.json in Resources */ = {isa = PBXBuildFile; fileRef = CE2678422A26102A00FD9AEB /* order-alternative-types.json */; };
644645
CE43066A23465F340073CBFF /* Refund.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE43066923465F340073CBFF /* Refund.swift */; };
645646
CE43066C2347C5F90073CBFF /* OrderItemRefund.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE43066B2347C5F90073CBFF /* OrderItemRefund.swift */; };
646647
CE43066E2347CBA70073CBFF /* OrderItemTaxRefund.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE43066D2347CBA70073CBFF /* OrderItemTaxRefund.swift */; };
@@ -1579,6 +1580,7 @@
15791580
CE19CB10222486A500E8AF7A /* order-statuses.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "order-statuses.json"; sourceTree = "<group>"; };
15801581
CE20179220E3EFA7005B4C18 /* broken-orders.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "broken-orders.json"; sourceTree = "<group>"; };
15811582
CE227092228DD44C00C0626C /* ProductStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductStatus.swift; sourceTree = "<group>"; };
1583+
CE2678422A26102A00FD9AEB /* order-alternative-types.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "order-alternative-types.json"; sourceTree = "<group>"; };
15821584
CE43066923465F340073CBFF /* Refund.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Refund.swift; sourceTree = "<group>"; };
15831585
CE43066B2347C5F90073CBFF /* OrderItemRefund.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderItemRefund.swift; sourceTree = "<group>"; };
15841586
CE43066D2347CBA70073CBFF /* OrderItemTaxRefund.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderItemTaxRefund.swift; sourceTree = "<group>"; };
@@ -2541,6 +2543,7 @@
25412543
B554FA8C2180B59700C54DFF /* notifications-load-hashes.json */,
25422544
AE2D6624272A941C004A2C3A /* null-data.json */,
25432545
B5C6FCD520A3768900A4F8E4 /* order.json */,
2546+
CE2678422A26102A00FD9AEB /* order-alternative-types.json */,
25442547
DEF13C5F29668C420024A02B /* order-without-data.json */,
25452548
034480C227A42F9100DFACD2 /* order-with-charge.json */,
25462549
02C254D62563999200A04423 /* order-shipping-labels.json */,
@@ -3620,6 +3623,7 @@
36203623
74ABA1C9213F19FE00FFAD30 /* top-performers-month.json in Resources */,
36213624
3158FE7026129D7500E566B9 /* wcpay-account-rejected-listed.json in Resources */,
36223625
743E84F622172D3E00FAC9D7 /* shipment_tracking_single.json in Resources */,
3626+
CE2678432A26102A00FD9AEB /* order-alternative-types.json in Resources */,
36233627
D865CE5B278CA10B002C8520 /* stripe-payment-intent-requires-payment-method.json in Resources */,
36243628
CC9A254626442CA7005DE56E /* shipping-label-eligibility-failure.json in Resources */,
36253629
4524CD9C242CEFAB00B2F20A /* product-on-sale-with-empty-sale-price.json in Resources */,

Networking/Networking/Model/OrderItem.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,11 @@ public struct OrderItem: Codable, Equatable, Hashable, GeneratedFakeable, Genera
8888
let decimalPrice = try container.decodeIfPresent(Decimal.self, forKey: .price) ?? Decimal(0)
8989
let price = NSDecimalNumber(decimal: decimalPrice)
9090

91-
let sku = try container.decodeIfPresent(String.self, forKey: .sku)
91+
// Even though a plain install of WooCommerce Core provides String values,
92+
// some plugins alter the field value from String to Int or Decimal.
93+
let sku = container.failsafeDecodeIfPresent(targetType: String.self,
94+
forKey: .sku,
95+
alternativeTypes: [.decimal(transform: { NSDecimalNumber(decimal: $0).stringValue })])
9296
let subtotal = try container.decode(String.self, forKey: .subtotal)
9397
let subtotalTax = try container.decode(String.self, forKey: .subtotalTax)
9498
let taxClass = try container.decode(String.self, forKey: .taxClass)

Networking/Networking/Model/ShippingLineTax.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,22 @@ public struct ShippingLineTax: Decodable, Hashable, GeneratedFakeable {
2424
self.subtotal = subtotal
2525
self.total = total
2626
}
27+
28+
/// The public initializer for ShippingLineTax.
29+
///
30+
public init(from decoder: Decoder) throws {
31+
let container = try decoder.container(keyedBy: CodingKeys.self)
32+
33+
// Even though a plain install of WooCommerce Core provides Int values,
34+
// some plugins alter the field value from Int to String.
35+
let taxID = container.failsafeDecodeIfPresent(targetType: Int64.self,
36+
forKey: .taxID,
37+
alternativeTypes: [.string(transform: { Int64($0) ?? 0 })]) ?? 0
38+
let subtotal = try container.decode(String.self, forKey: .subtotal)
39+
let total = try container.decode(String.self, forKey: .total)
40+
41+
self.init(taxID: taxID, subtotal: subtotal, total: total)
42+
}
2743
}
2844

2945
/// Defines all of the ShippingLineTax CodingKeys.

Networking/NetworkingTests/Mapper/OrderMapperTests.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,15 @@ final class OrderMapperTests: XCTestCase {
429429
XCTAssertNil(compositeProduct.parent)
430430
XCTAssertEqual(component.parent, 830)
431431
}
432+
433+
func test_that_order_alternative_types_are_properly_parsed() throws {
434+
// Given
435+
let order = try XCTUnwrap(mapLoadOrderResponseWithAlternativeTypes())
436+
437+
// Then
438+
XCTAssertEqual(order.shippingLines.first?.taxes.first?.taxID, 1)
439+
XCTAssertEqual(order.items.first?.sku, "123")
440+
}
432441
}
433442

434443

@@ -531,4 +540,10 @@ private extension OrderMapperTests {
531540
return mapOrder(from: "order-with-composite-product")
532541
}
533542

543+
/// Returns the Order output upon receiving `order-alternative-types`
544+
///
545+
func mapLoadOrderResponseWithAlternativeTypes() -> Order? {
546+
return mapOrder(from: "order-alternative-types")
547+
}
548+
534549
}
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
{
2+
"data": {
3+
"id": 963,
4+
"parent_id": 0,
5+
"is_editable": true,
6+
"needs_payment": true,
7+
"needs_processing": true,
8+
"number": "963",
9+
"status": "processing",
10+
"order_key": "abc123",
11+
"currency": "USD",
12+
"date_created_gmt": "2018-04-03T23:05:12",
13+
"date_modified_gmt": "2018-04-03T23:05:14",
14+
"discount_total": "30.00",
15+
"discount_tax": "1.20",
16+
"shipping_total": "0.00",
17+
"shipping_tax": "0.00",
18+
"cart_tax": "1.20",
19+
"total": "31.20",
20+
"total_tax": "1.20",
21+
"customer_id": 11,
22+
"customer_note": "",
23+
"billing": {
24+
"first_name": "Johnny",
25+
"last_name": "Appleseed",
26+
"company": "",
27+
"address_1": "234 70th Street",
28+
"address_2": "",
29+
"city": "Niagara Falls",
30+
"state": "NY",
31+
"postcode": "14304",
32+
"country": "US",
33+
"email": "[email protected]",
34+
"phone": "333-333-3333"
35+
},
36+
"shipping": {
37+
"first_name": "Johnny",
38+
"last_name": "Appleseed",
39+
"company": "",
40+
"address_1": "234 70th Street",
41+
"address_2": "",
42+
"city": "Niagara Falls",
43+
"state": "NY",
44+
"postcode": "14304",
45+
"country": "US",
46+
"email": "[email protected]",
47+
"phone": "333-333-3333"
48+
},
49+
"shipping_lines": [
50+
{
51+
"id": 123,
52+
"method_title": "International Priority Mail Express Flat Rate",
53+
"method_id": "usps",
54+
"instance_id": "5",
55+
"total": "133.00",
56+
"total_tax": "0.00",
57+
"taxes": [
58+
{
59+
"id": "1",
60+
"total": "0.62125",
61+
"subtotal": ""
62+
}
63+
],
64+
"meta_data": [
65+
{
66+
"id": 1307,
67+
"key": "Package 1",
68+
"value": "1 × 1 × 1 (in) 4lbs × 1"
69+
},
70+
{
71+
"id": 1308,
72+
"key": "Package 2",
73+
"value": "1 × 1 × 1 (in) 1lbs × 1"
74+
}
75+
]
76+
}
77+
],
78+
"fee_lines": [
79+
{
80+
"id": 60,
81+
"name": "$125.50 fee",
82+
"tax_class": "",
83+
"tax_status": "taxable",
84+
"amount": "125.5",
85+
"total": "125.50",
86+
"total_tax": "0.00",
87+
"taxes": [],
88+
"meta_data": []
89+
}
90+
],
91+
"tax_lines": [
92+
{
93+
"id": 1330,
94+
"rate_code": "US-NY-STATE-2",
95+
"rate_id": 6,
96+
"label": "State",
97+
"compound": true,
98+
"tax_total": "7.71",
99+
"shipping_tax_total": "0.00",
100+
"rate_percent": 4.5,
101+
"meta_data": []
102+
}
103+
],
104+
"payment_method": "stripe",
105+
"payment_method_title": "Credit Card (Stripe)",
106+
"payment_url": "http://www.automattic.com",
107+
"date_paid_gmt": "2018-04-03T23:05:14",
108+
"date_completed_gmt": null,
109+
"line_items": [
110+
{
111+
"id": 890,
112+
"name": "Fruits Basket (Mix & Match Product)",
113+
"product_id": 52,
114+
"variation_id": 0,
115+
"quantity": 2,
116+
"tax_class": "",
117+
"subtotal": "50.00",
118+
"subtotal_tax": "2.00",
119+
"total": "30.00",
120+
"total_tax": "1.20",
121+
"taxes": [
122+
{
123+
"id": 1,
124+
"total": "1.2",
125+
"subtotal": "2"
126+
}
127+
],
128+
"meta_data": [],
129+
"sku": 123,
130+
"price": 30
131+
},
132+
{
133+
"id": 891,
134+
"name": "Fruits Bundle",
135+
"product_id": 234,
136+
"variation_id": 0,
137+
"quantity": 1.5,
138+
"tax_class": "",
139+
"subtotal": "10.00",
140+
"subtotal_tax": "0.40",
141+
"total": "0.00",
142+
"total_tax": "0.00",
143+
"taxes": [
144+
{
145+
"id": 1,
146+
"total": "0",
147+
"subtotal": "0.4"
148+
}
149+
],
150+
"meta_data": [],
151+
"sku": "5555-A",
152+
"price": 0.00
153+
}
154+
],
155+
"coupon_lines": [
156+
{
157+
"id": 894,
158+
"code": "30$off",
159+
"discount": "30",
160+
"discount_tax": "1.2",
161+
"meta_data": [
162+
{
163+
"id": 6515,
164+
"key": "coupon_data",
165+
"value": {
166+
"id": 673,
167+
"code": "30$off",
168+
"amount": "30",
169+
"date_created": {
170+
"date": "2017-10-29 18:20:07.000000",
171+
"timezone_type": 3,
172+
"timezone": "America/New_York"
173+
},
174+
"date_modified": {
175+
"date": "2017-10-29 18:20:07.000000",
176+
"timezone_type": 3,
177+
"timezone": "America/New_York"
178+
},
179+
"date_expires": null,
180+
"discount_type": "fixed_cart",
181+
"description": "",
182+
"usage_count": 2,
183+
"individual_use": false,
184+
"product_ids": [],
185+
"excluded_product_ids": [],
186+
"usage_limit": 0,
187+
"usage_limit_per_user": 0,
188+
"limit_usage_to_x_items": null,
189+
"free_shipping": false,
190+
"product_categories": [],
191+
"excluded_product_categories": [],
192+
"exclude_sale_items": false,
193+
"minimum_amount": "",
194+
"maximum_amount": "",
195+
"email_restrictions": [],
196+
"used_by": [
197+
"1",
198+
"1"
199+
],
200+
"virtual": false,
201+
"meta_data": []
202+
}
203+
}
204+
]
205+
}
206+
]
207+
}
208+
}
209+

RELEASE-NOTES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
13.9
44
-----
5+
- [*] 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]
56
- [*] 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]
67

78
13.8

0 commit comments

Comments
 (0)