Skip to content

Commit a214f22

Browse files
authored
Merge pull request #9780 from woocommerce/issue/8963-composite-product-hierarchy
2 parents 898af02 + f0b72d1 commit a214f22

File tree

5 files changed

+205
-1
lines changed

5 files changed

+205
-1
lines changed

Networking/Networking.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,7 @@
659659
CE6BFEEA2236E191005C79FB /* ProductType.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE6BFEE92236E191005C79FB /* ProductType.swift */; };
660660
CE6D666C2379E19D007835A1 /* Array+Woo.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE6D666B2379E19D007835A1 /* Array+Woo.swift */; };
661661
CE6D666F2379E82A007835A1 /* ArrayWooTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE6D666E2379E82A007835A1 /* ArrayWooTests.swift */; };
662+
CE831FE72A17FC1800E8BEFB /* order-with-composite-product.json in Resources */ = {isa = PBXBuildFile; fileRef = CE831FE62A17FC1800E8BEFB /* order-with-composite-product.json */; };
662663
CEC4BF8F234E382F008D9195 /* RefundMapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC4BF8E234E382F008D9195 /* RefundMapperTests.swift */; };
663664
CEC4BF91234E40B5008D9195 /* refund-single.json in Resources */ = {isa = PBXBuildFile; fileRef = CEC4BF90234E40B5008D9195 /* refund-single.json */; };
664665
CEC4BF93234E7EE0008D9195 /* refunds-all.json in Resources */ = {isa = PBXBuildFile; fileRef = CEC4BF92234E7EE0008D9195 /* refunds-all.json */; };
@@ -1596,6 +1597,7 @@
15961597
CE6BFEE92236E191005C79FB /* ProductType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductType.swift; sourceTree = "<group>"; };
15971598
CE6D666B2379E19D007835A1 /* Array+Woo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Woo.swift"; sourceTree = "<group>"; };
15981599
CE6D666E2379E82A007835A1 /* ArrayWooTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayWooTests.swift; sourceTree = "<group>"; };
1600+
CE831FE62A17FC1800E8BEFB /* order-with-composite-product.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "order-with-composite-product.json"; sourceTree = "<group>"; };
15991601
CEC4BF8E234E382F008D9195 /* RefundMapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefundMapperTests.swift; sourceTree = "<group>"; };
16001602
CEC4BF90234E40B5008D9195 /* refund-single.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "refund-single.json"; sourceTree = "<group>"; };
16011603
CEC4BF92234E7EE0008D9195 /* refunds-all.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "refunds-all.json"; sourceTree = "<group>"; };
@@ -2565,6 +2567,7 @@
25652567
CE12AE9429F29F4F0056DD17 /* order-with-subscription-renewal.json */,
25662568
CEE9188029F7DC23004B23FF /* order-with-gift-cards.json */,
25672569
CE6B96992A0BCD09003C4B27 /* order-with-bundled-line-items.json */,
2570+
CE831FE62A17FC1800E8BEFB /* order-with-composite-product.json */,
25682571
261CF1B3255AD6B30090D8D3 /* payment-gateway-list.json */,
25692572
0313651A28AE60E000EEE571 /* payment-gateway-cod.json */,
25702573
261CF2CA255C50010090D8D3 /* payment-gateway-list-half.json */,
@@ -3652,6 +3655,7 @@
36523655
45AB8B0F24AA29DC00B5B36E /* product-tags-created.json in Resources */,
36533656
3158FE8426129F3A00E566B9 /* wcpay-account-unknown-status.json in Resources */,
36543657
621D043B29C9D4280040EC08 /* product-variation-alternative-types.json in Resources */,
3658+
CE831FE72A17FC1800E8BEFB /* order-with-composite-product.json in Resources */,
36553659
314EDF2B27C02CD300A56B6F /* stripe-account-complete-null-descriptor.json in Resources */,
36563660
31054720262E2F9D00C5C02B /* wcpay-payment-intent-processing.json in Resources */,
36573661
0239306D291A973F00B2632F /* domain-suggestions.json in Resources */,

Networking/Networking/Model/OrderItem.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,11 @@ public struct OrderItem: Codable, Equatable, Hashable, GeneratedFakeable, Genera
105105
// If it's not a bundled item, the API returns an empty string for `bundledBy` and the value will be `nil`.
106106
let bundledBy = container.failsafeDecodeIfPresent(Int64.self, forKey: .bundledBy)
107107

108+
// Composite Products extension properties:
109+
// If the order item is a composite component, `compositeParent` is the parent order item (composite product).
110+
// If it's not a composite component, the API returns an empty string for `compositeParent` and the value will be `nil`.
111+
let compositeParent = container.failsafeDecodeIfPresent(Int64.self, forKey: .compositeParent)
112+
108113
// initialize the struct
109114
self.init(itemID: itemID,
110115
name: name,
@@ -120,7 +125,7 @@ public struct OrderItem: Codable, Equatable, Hashable, GeneratedFakeable, Genera
120125
total: total,
121126
totalTax: totalTax,
122127
attributes: attributes,
123-
parent: bundledBy)
128+
parent: bundledBy ?? compositeParent)
124129
}
125130

126131
/// Encodes an order item.
@@ -168,6 +173,7 @@ extension OrderItem {
168173
case total
169174
case totalTax = "total_tax"
170175
case bundledBy = "bundled_by"
176+
case compositeParent = "composite_parent"
171177
}
172178
}
173179

Networking/NetworkingTests/Mapper/OrderMapperTests.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,21 @@ final class OrderMapperTests: XCTestCase {
414414
XCTAssertNil(bundleItem.parent)
415415
XCTAssertEqual(bundledItem.parent, 752)
416416
}
417+
418+
func test_order_line_items_parse_composite_product_component_parent_correctly() throws {
419+
// Given
420+
let order = try XCTUnwrap(mapLoadOrderWithCompositeProduct())
421+
422+
// When
423+
let lineItems = order.items
424+
XCTAssertEqual(lineItems.count, 4)
425+
426+
// Then
427+
let compositeProduct = try XCTUnwrap(lineItems.first { $0.itemID == 830 })
428+
let component = try XCTUnwrap(lineItems.first { $0.itemID == 831 })
429+
XCTAssertNil(compositeProduct.parent)
430+
XCTAssertEqual(component.parent, 830)
431+
}
417432
}
418433

419434

@@ -510,4 +525,10 @@ private extension OrderMapperTests {
510525
return mapOrder(from: "order-with-bundled-line-items")
511526
}
512527

528+
/// Returns the Order output upon receiving `order-with-composite-product`
529+
///
530+
func mapLoadOrderWithCompositeProduct() -> Order? {
531+
return mapOrder(from: "order-with-composite-product")
532+
}
533+
513534
}
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
{
2+
"data": {
3+
"id": 421,
4+
"parent_id": 0,
5+
"status": "processing",
6+
"currency": "USD",
7+
"version": "7.5.0",
8+
"prices_include_tax": false,
9+
"date_created": "2023-03-20T11:20:18",
10+
"date_modified": "2023-03-20T11:21:40",
11+
"discount_total": "0.00",
12+
"discount_tax": "0.00",
13+
"shipping_total": "0.00",
14+
"shipping_tax": "0.00",
15+
"cart_tax": "0.00",
16+
"total": "2300.00",
17+
"total_tax": "0.00",
18+
"customer_id": 0,
19+
"order_key": "wc_order_ny80Lejd0xLvs",
20+
"billing": {
21+
"first_name": "",
22+
"last_name": "",
23+
"company": "",
24+
"address_1": "",
25+
"address_2": "",
26+
"city": "",
27+
"state": "",
28+
"postcode": "",
29+
"country": "",
30+
"email": "",
31+
"phone": ""
32+
},
33+
"shipping": {
34+
"first_name": "",
35+
"last_name": "",
36+
"company": "",
37+
"address_1": "",
38+
"address_2": "",
39+
"city": "",
40+
"state": "",
41+
"postcode": "",
42+
"country": ""
43+
},
44+
"payment_method": "",
45+
"payment_method_title": "",
46+
"transaction_id": "",
47+
"customer_ip_address": "",
48+
"customer_user_agent": "",
49+
"created_via": "admin",
50+
"customer_note": "",
51+
"date_completed": null,
52+
"date_paid": "2023-03-20T11:21:40",
53+
"cart_hash": "",
54+
"number": "421",
55+
"meta_data": [],
56+
"line_items": [
57+
{
58+
"id": 830,
59+
"name": "Full Frame DSLR Kit",
60+
"product_id": 419,
61+
"variation_id": 0,
62+
"quantity": 1,
63+
"tax_class": "",
64+
"subtotal": "2300.00",
65+
"subtotal_tax": "0.00",
66+
"total": "2300.00",
67+
"total_tax": "0.00",
68+
"taxes": [],
69+
"meta_data": [],
70+
"sku": "",
71+
"price": 2300,
72+
"parent_name": null,
73+
"composite_parent": "",
74+
"composite_children": [
75+
831,
76+
832,
77+
833
78+
]
79+
},
80+
{
81+
"id": 831,
82+
"name": "Canon EOS 5D Mark IV Camera Body",
83+
"product_id": 413,
84+
"variation_id": 0,
85+
"quantity": 1,
86+
"tax_class": "",
87+
"subtotal": "0.00",
88+
"subtotal_tax": "0.00",
89+
"total": "0.00",
90+
"total_tax": "0.00",
91+
"taxes": [],
92+
"meta_data": [],
93+
"sku": "",
94+
"price": 0,
95+
"parent_name": null,
96+
"composite_parent": 830,
97+
"composite_children": []
98+
},
99+
{
100+
"id": 832,
101+
"name": "Canon EF 70-200MM F:2.8 L USM",
102+
"product_id": 417,
103+
"variation_id": 0,
104+
"quantity": 1,
105+
"tax_class": "",
106+
"subtotal": "0.00",
107+
"subtotal_tax": "0.00",
108+
"total": "0.00",
109+
"total_tax": "0.00",
110+
"taxes": [],
111+
"meta_data": [],
112+
"sku": "",
113+
"price": 0,
114+
"parent_name": null,
115+
"composite_parent": 830,
116+
"composite_children": []
117+
},
118+
{
119+
"id": 833,
120+
"name": "16GB CompactFlash Card",
121+
"product_id": 418,
122+
"variation_id": 0,
123+
"quantity": 1,
124+
"tax_class": "",
125+
"subtotal": "0.00",
126+
"subtotal_tax": "0.00",
127+
"total": "0.00",
128+
"total_tax": "0.00",
129+
"taxes": [],
130+
"meta_data": [],
131+
"sku": "",
132+
"price": 0,
133+
"parent_name": null,
134+
"composite_parent": 830,
135+
"composite_children": []
136+
}
137+
],
138+
"tax_lines": [],
139+
"shipping_lines": [],
140+
"fee_lines": [],
141+
"coupon_lines": [],
142+
"refunds": [],
143+
"payment_url": "https://example.com/checkout/order-pay/421/?pay_for_order=true&key=wc_order_abcd1234",
144+
"is_editable": false,
145+
"needs_payment": false,
146+
"needs_processing": true,
147+
"date_created_gmt": "2023-03-20T11:20:18",
148+
"date_modified_gmt": "2023-03-20T11:21:40",
149+
"date_completed_gmt": null,
150+
"date_paid_gmt": "2023-03-20T11:21:40",
151+
"gift_cards": [],
152+
"currency_symbol": "$",
153+
"_links": {
154+
"self": [
155+
{
156+
"href": "https://example.com/wp-json/wc/v3/orders/421"
157+
}
158+
],
159+
"collection": [
160+
{
161+
"href": "https://example.com/wp-json/wc/v3/orders"
162+
}
163+
],
164+
"customer": [
165+
{
166+
"href": "https://example.com/wp-json/wc/v3/customers/27375291"
167+
}
168+
]
169+
}
170+
}
171+
}

RELEASE-NOTES.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
13.8
44
-----
55
- [Internal] Orders: Bundled products (within a product bundle) are now indented, to show their relationship to the parent bundle. [https://github.com/woocommerce/woocommerce-ios/pull/9778]
6+
- [Internal] Orders: Composite components (within a composite product) are now indented, to show their relationship to the parent composite product. [https://github.com/woocommerce/woocommerce-ios/pull/9780]
67
- [*] Add Products: A new view is display to celebrate when the first product is created in a store. [https://github.com/woocommerce/woocommerce-ios/pull/9790]
78
- [*] Product form: a share action is shown in the navigation bar if the product can be shared and no more than one action is displayed, in addition to the more menu > Share. [https://github.com/woocommerce/woocommerce-ios/pull/9789]
89

@@ -16,6 +17,7 @@
1617
- [**] Mobile Payments: Tap to Pay is initialised on launch or foreground, to speed up payments [https://github.com/woocommerce/woocommerce-ios/pull/9750]
1718
- [*] Store Creation: Local notifications are used to support users during the store creation process. [https://github.com/woocommerce/woocommerce-ios/pull/9717, https://github.com/woocommerce/woocommerce-ios/pull/9719, https://github.com/woocommerce/woocommerce-ios/pull/9749]
1819
- [**] Mobile Payments: Merchants can now collect in-person payments by showing a QR code to their customers. [https://github.com/woocommerce/woocommerce-ios/pull/9762]
20+
- [Internal] Orders: Bundled products (within a product bundle) are now indented, to show their relationship to the parent bundle. [https://github.com/woocommerce/woocommerce-ios/pull/9778]
1921

2022
13.6
2123
-----

0 commit comments

Comments
 (0)