Skip to content

Commit 45f2f53

Browse files
committed
Merge branch 'trunk' into task/15065-failed-uploads-screen
2 parents 55750ce + 3fe7850 commit 45f2f53

32 files changed

+643
-125
lines changed

Fakes/Fakes/Networking.generated.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2369,6 +2369,21 @@ extension Networking.StoredProductSettings {
23692369
)
23702370
}
23712371
}
2372+
extension Networking.StoredProductSettings.Setting {
2373+
/// Returns a "ready to use" type filled with fake values.
2374+
///
2375+
public static func fake() -> Networking.StoredProductSettings.Setting {
2376+
.init(
2377+
siteID: .fake(),
2378+
sort: .fake(),
2379+
stockStatusFilter: .fake(),
2380+
productStatusFilter: .fake(),
2381+
productTypeFilter: .fake(),
2382+
productCategoryFilter: .fake(),
2383+
favoriteProduct: .fake()
2384+
)
2385+
}
2386+
}
23722387
extension Networking.Subscription {
23732388
/// Returns a "ready to use" type filled with fake values.
23742389
///

Networking/Networking.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,7 @@
454454
451A97E9260B657D0059D135 /* ShippingLabelPredefinedOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451A97E8260B657D0059D135 /* ShippingLabelPredefinedOption.swift */; };
455455
451A9832260B9D2D0059D135 /* ShippingLabelPackagesMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451A9831260B9D2D0059D135 /* ShippingLabelPackagesMapper.swift */; };
456456
451A9836260B9DF90059D135 /* ShippingLabelPackagesMapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451A9835260B9DF90059D135 /* ShippingLabelPackagesMapperTests.swift */; };
457+
4523FB872D596F8000FD1328 /* order-shipping-labels-with-error-in-labels-data.json in Resources */ = {isa = PBXBuildFile; fileRef = 4523FB862D596F6300FD1328 /* order-shipping-labels-with-error-in-labels-data.json */; };
457458
4524CD9C242CEFAB00B2F20A /* product-on-sale-with-empty-sale-price.json in Resources */ = {isa = PBXBuildFile; fileRef = 4524CD9B242CEFAB00B2F20A /* product-on-sale-with-empty-sale-price.json */; };
458459
453305E92459DF2100264E50 /* PostMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 453305E82459DF2100264E50 /* PostMapper.swift */; };
459460
453305EB2459E01A00264E50 /* PostMapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 453305EA2459E01A00264E50 /* PostMapperTests.swift */; };
@@ -1655,6 +1656,7 @@
16551656
451A97E8260B657D0059D135 /* ShippingLabelPredefinedOption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingLabelPredefinedOption.swift; sourceTree = "<group>"; };
16561657
451A9831260B9D2D0059D135 /* ShippingLabelPackagesMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingLabelPackagesMapper.swift; sourceTree = "<group>"; };
16571658
451A9835260B9DF90059D135 /* ShippingLabelPackagesMapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingLabelPackagesMapperTests.swift; sourceTree = "<group>"; };
1659+
4523FB862D596F6300FD1328 /* order-shipping-labels-with-error-in-labels-data.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "order-shipping-labels-with-error-in-labels-data.json"; sourceTree = "<group>"; };
16581660
4524CD9B242CEFAB00B2F20A /* product-on-sale-with-empty-sale-price.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "product-on-sale-with-empty-sale-price.json"; sourceTree = "<group>"; };
16591661
453305E82459DF2100264E50 /* PostMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostMapper.swift; sourceTree = "<group>"; };
16601662
453305EA2459E01A00264E50 /* PostMapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostMapperTests.swift; sourceTree = "<group>"; };
@@ -3339,6 +3341,7 @@
33393341
DEF13C5F29668C420024A02B /* order-without-data.json */,
33403342
034480C227A42F9100DFACD2 /* order-with-charge.json */,
33413343
02C254D62563999200A04423 /* order-shipping-labels.json */,
3344+
4523FB862D596F6300FD1328 /* order-shipping-labels-with-error-in-labels-data.json */,
33423345
B559EBA920A0B5CD00836CD4 /* orders-load-all.json */,
33433346
01F42C0A2CE1ECB7003D0A5A /* orders-actions-send-order-details.json */,
33443347
DEF13C5D296686AB0024A02B /* orders-load-all-without-data.json */,
@@ -4481,6 +4484,7 @@
44814484
CE12AE9B29F2AC3C0056DD17 /* subscription-without-data.json in Resources */,
44824485
028FA474257E110700F88A48 /* shipping-label-refund-success.json in Resources */,
44834486
DE74F29C27E0A1D00002FE59 /* setting-coupon.json in Resources */,
4487+
4523FB872D596F8000FD1328 /* order-shipping-labels-with-error-in-labels-data.json in Resources */,
44844488
EE8A86F1286C5226003E8AA4 /* media-update-product-id-in-wordpress-site.json in Resources */,
44854489
02BA23C922EEF62C009539E7 /* order-stats-v4-wcadmin-deactivated.json in Resources */,
44864490
CCB2CAA226209A1200285CA0 /* generic_success_data.json in Resources */,

Networking/Networking/Mapper/OrderShippingLabelListMapper.swift

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,10 @@ private struct OrderShippingLabelListData: Decodable {
8585

8686
// Shipping labels.
8787
let formData = try container.decode(OrderShippingLabelListFormData.self, forKey: .formData)
88-
let shippingLabelsWithoutAddresses = try container.decode([ShippingLabel].self, forKey: .labelsData)
88+
89+
// Use a helper method to decode shipping labels without errors.
90+
let shippingLabelsWithoutAddresses = try Self.decodeShippingLabelsWithoutErrors(from: container, siteID: siteID, orderID: orderID)
91+
8992
// Filters only labels with a tracking number and status `.purchased`.
9093
// Then populates each shipping label's `originAddress` and `destinationAddress` from `formData` because they are not available
9194
// in each shipping label response.
@@ -98,10 +101,35 @@ private struct OrderShippingLabelListData: Decodable {
98101
self.init(shippingLabels: shippingLabels, settings: settings)
99102
}
100103

104+
/// Helper method to decode shipping labels filtering out any labels with an error.
105+
private static func decodeShippingLabelsWithoutErrors(from container: KeyedDecodingContainer<CodingKeys>,
106+
siteID: Int64,
107+
orderID: Int64) throws -> [ShippingLabel] {
108+
// Decode the labelsData as an array of dictionaries,
109+
// and filter out labels that have an "error" key
110+
// then convert the filtered array of dictionaries to JSON data.
111+
// This matches the web behavior that doesn't display shipping labels error,
112+
// that are sent together in `labelsData` array.
113+
var labelsData = try container.decode([[String: AnyCodable]].self, forKey: .labelsData)
114+
labelsData = labelsData.filter { $0[CodingKeys.errorKey] == nil }
115+
116+
let encoder = JSONEncoder()
117+
let filteredLabelsData = try encoder.encode(labelsData)
118+
119+
let decoder = JSONDecoder()
120+
decoder.dateDecodingStrategy = .millisecondsSince1970
121+
decoder.userInfo = [
122+
.siteID: siteID,
123+
.orderID: orderID
124+
]
125+
return try decoder.decode([ShippingLabel].self, from: filteredLabelsData)
126+
}
127+
101128
private enum CodingKeys: String, CodingKey {
102129
case formData
103130
case paperSize
104131
case labelsData
132+
static let errorKey = "error"
105133
}
106134
}
107135

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3502,6 +3502,36 @@ extension Networking.SiteVisitStatsItem {
35023502
}
35033503
}
35043504

3505+
extension Networking.StoredProductSettings.Setting {
3506+
public func copy(
3507+
siteID: CopiableProp<Int64> = .copy,
3508+
sort: NullableCopiableProp<String> = .copy,
3509+
stockStatusFilter: NullableCopiableProp<ProductStockStatus> = .copy,
3510+
productStatusFilter: NullableCopiableProp<ProductStatus> = .copy,
3511+
productTypeFilter: NullableCopiableProp<ProductType> = .copy,
3512+
productCategoryFilter: NullableCopiableProp<ProductCategory> = .copy,
3513+
favoriteProduct: CopiableProp<Bool> = .copy
3514+
) -> Networking.StoredProductSettings.Setting {
3515+
let siteID = siteID ?? self.siteID
3516+
let sort = sort ?? self.sort
3517+
let stockStatusFilter = stockStatusFilter ?? self.stockStatusFilter
3518+
let productStatusFilter = productStatusFilter ?? self.productStatusFilter
3519+
let productTypeFilter = productTypeFilter ?? self.productTypeFilter
3520+
let productCategoryFilter = productCategoryFilter ?? self.productCategoryFilter
3521+
let favoriteProduct = favoriteProduct ?? self.favoriteProduct
3522+
3523+
return Networking.StoredProductSettings.Setting(
3524+
siteID: siteID,
3525+
sort: sort,
3526+
stockStatusFilter: stockStatusFilter,
3527+
productStatusFilter: productStatusFilter,
3528+
productTypeFilter: productTypeFilter,
3529+
productCategoryFilter: productCategoryFilter,
3530+
favoriteProduct: favoriteProduct
3531+
)
3532+
}
3533+
}
3534+
35053535
extension Networking.Subscription {
35063536
public func copy(
35073537
siteID: CopiableProp<Int64> = .copy,

Networking/Networking/Model/Product/StoredProductSettings.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import Codegen
66
///
77
public struct StoredProductSettings: Codable, Equatable, GeneratedFakeable {
88

9-
public struct Setting: Codable, Equatable {
9+
public struct Setting: Codable, Equatable, GeneratedFakeable, GeneratedCopiable {
1010
public let siteID: Int64
1111
public let sort: String?
1212
public let stockStatusFilter: ProductStockStatus?

Networking/NetworkingTests/Mapper/OrderShippingLabelListMapperTests.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,17 @@ final class OrderShippingLabelListMapperTests: XCTestCase {
8888
XCTAssertEqual(response.settings, .init(siteID: sampleSiteID, orderID: sampleOrderID, paperSize: .label))
8989
XCTAssertEqual(response.shippingLabels.count, 1)
9090
}
91+
92+
func test_order_shipping_labels_mapper_filters_out_labels_with_error_in_labelsData() throws {
93+
// Given
94+
let jsonData = try XCTUnwrap(Loader.contentsOf("order-shipping-labels-with-error-in-labels-data"))
95+
96+
// When
97+
let response = try OrderShippingLabelListMapper(siteID: sampleSiteID, orderID: sampleOrderID).map(response: jsonData)
98+
99+
// Then
100+
XCTAssertEqual(response.settings, .init(siteID: sampleSiteID, orderID: sampleOrderID, paperSize: .label))
101+
XCTAssertEqual(response.shippingLabels.count, 3)
102+
XCTAssertFalse(response.shippingLabels.contains { $0.shippingLabelID == 4697 }, "Labels with error should be filtered out")
103+
}
91104
}
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
{
2+
"data" : {
3+
"orderId" : 1530,
4+
"labelsData" : [
5+
{
6+
"expiry_date" : 1754682728000,
7+
"status" : "PURCHASED",
8+
"is_letter" : false,
9+
"refundable_amount" : 8.9499999999999993,
10+
"service_name" : "USPS - Priority Mail",
11+
"receipt_item_id" : 25072191,
12+
"created_date" : 1739130728000,
13+
"label_id" : 4730,
14+
"commercial_invoice_url" : "",
15+
"currency" : "USD",
16+
"main_receipt_id" : 20298316,
17+
"product_ids" : [
18+
58,
19+
733
20+
],
21+
"product_names" : [
22+
"Mojito",
23+
"Gin Tonic"
24+
],
25+
"package_name" : "Small Flat Rate Box",
26+
"id" : "0",
27+
"tracking" : "9405500106025109446438",
28+
"is_commercial_invoice_submitted_electronically" : false,
29+
"rate" : 8.9499999999999993,
30+
"created" : 1739130724150,
31+
"carrier_id" : "usps"
32+
},
33+
{
34+
"currency" : "USD",
35+
"product_names" : [
36+
"Mojito",
37+
"Gin Tonic"
38+
],
39+
"expiry_date" : 1754402449000,
40+
"product_ids" : [
41+
58,
42+
733
43+
],
44+
"service_name" : "USPS - Media Mail",
45+
"tracking" : "9449000106025109444891",
46+
"label_id" : 4709,
47+
"created_date" : 1738850450000,
48+
"package_name" : "Unknown package",
49+
"is_letter" : false,
50+
"receipt_item_id" : 25071198,
51+
"is_commercial_invoice_submitted_electronically" : false,
52+
"created" : 1738850446604,
53+
"refundable_amount" : 6.8799999999999999,
54+
"commercial_invoice_url" : "",
55+
"carrier_id" : "usps",
56+
"rate" : 6.8799999999999999,
57+
"status" : "PURCHASED",
58+
"main_receipt_id" : 20297330
59+
},
60+
{
61+
"currency" : "USD",
62+
"product_names" : [
63+
"Mojito",
64+
"Gin Tonic"
65+
],
66+
"expiry_date" : 1754395743000,
67+
"product_ids" : [
68+
58,
69+
733
70+
],
71+
"service_name" : "USPS - Media Mail",
72+
"tracking" : "9449000106025109444860",
73+
"label_id" : 4699,
74+
"created_date" : 1738843744000,
75+
"package_name" : "Unknown package",
76+
"is_letter" : false,
77+
"receipt_item_id" : 25071104,
78+
"is_commercial_invoice_submitted_electronically" : false,
79+
"created" : 1738843740105,
80+
"refundable_amount" : 6.8799999999999999,
81+
"commercial_invoice_url" : "",
82+
"carrier_id" : "usps",
83+
"rate" : 6.8799999999999999,
84+
"status" : "PURCHASED",
85+
"main_receipt_id" : 20297238
86+
},
87+
{
88+
"id" : "0",
89+
"product_names" : [
90+
"Mojito",
91+
"Gin Tonic"
92+
],
93+
"product_ids" : [
94+
58,
95+
733
96+
],
97+
"service_name" : "USPS - Ground Advantage",
98+
"error" : "Payment failed - 3D Secure (3DS) transactions are not currently supported. Please use a different payment method.",
99+
"tracking" : null,
100+
"label_id" : 4697,
101+
"created_date" : 1738841686000,
102+
"package_name" : "Small Flat Rate Box",
103+
"is_letter" : false,
104+
"receipt_item_id" : -1,
105+
"is_commercial_invoice_submitted_electronically" : false,
106+
"created" : 1738841686539,
107+
"refundable_amount" : 0,
108+
"commercial_invoice_url" : "",
109+
"carrier_id" : "usps",
110+
"status" : "PURCHASE_ERROR"
111+
}
112+
],
113+
"success" : true,
114+
"formData" : {
115+
"origin" : {
116+
"phone" : "12345678900",
117+
"address" : "60 29th Street #343",
118+
"country" : "US",
119+
"city" : "San Francisco",
120+
"company" : "Shut up and sip",
121+
"postcode" : "94110",
122+
"address_2" : "",
123+
"name" : "Paolo",
124+
"state" : "CA"
125+
},
126+
"destination" : {
127+
"phone" : "555-1234",
128+
"city" : "NEW YORK",
129+
"country" : "US",
130+
"address" : "20 W 34TH ST STE 100",
131+
"company" : "Shut up and sip",
132+
"postcode" : "10118-0114",
133+
"address_2" : "",
134+
"state" : "NY",
135+
"name" : "New York store"
136+
},
137+
"order_id" : 1530,
138+
"rates" : {
139+
"selected" : {
140+
141+
}
142+
},
143+
"selected_packages" : {
144+
"default_box" : {
145+
"box_id" : "not_selected",
146+
"height" : 0,
147+
"length" : 0,
148+
"id" : "default_box",
149+
"weight" : 1.5,
150+
"width" : 0,
151+
"items" : [
152+
{
153+
"quantity" : 1,
154+
"description" : "Mojito",
155+
"width" : 10,
156+
"url" : "https://example.com/wp-admin/post.php?post=58&action=edit",
157+
"weight" : 0.5,
158+
"length" : 10,
159+
"origin_country" : "US",
160+
"value" : 15,
161+
"product_id" : 58,
162+
"height" : 10,
163+
"hs_tariff_number" : "",
164+
"name" : "#58 - Mojito"
165+
},
166+
{
167+
"quantity" : 1,
168+
"description" : "Gin Tonic",
169+
"width" : 10,
170+
"url" : "https://example.com/wp-admin/post.php?post=733&action=edit",
171+
"weight" : 1,
172+
"length" : 0,
173+
"origin_country" : "US",
174+
"value" : 5,
175+
"product_id" : 733,
176+
"height" : 20,
177+
"hs_tariff_number" : "",
178+
"name" : "#733 - Gin Tonic"
179+
}
180+
]
181+
}
182+
},
183+
"origin_normalized" : true,
184+
"destination_normalized" : true,
185+
"is_packed" : true
186+
},
187+
"paperSize" : "label",
188+
"storeOptions" : {
189+
"origin_country" : "US",
190+
"dimension_unit" : "cm",
191+
"currency_symbol" : "$",
192+
"weight_unit" : "kg"
193+
},
194+
"canChangeCountries" : true
195+
}
196+
}

RELEASE-NOTES.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33

44
21.8
55
-----
6+
- [**] Shipping Labels: resolved issue preventing shipping labels from displaying in some orders when an error occurred during label creation. [https://github.com/woocommerce/woocommerce-ios/pull/15101]
67
- [*] Now "Suggested by AI" label is visible in dark mode in Blaze campaign creation flow. [https://github.com/woocommerce/woocommerce-ios/pull/15088]
78
- [*] Improved image loading in Blaze Campaign Creation: displays a redacted and shimmering effects when loading product image and falls back to a placeholder if no image is available. [https://github.com/woocommerce/woocommerce-ios/pull/15098]
89
- [*] Product List: Display syncing animation on items with image upload in progress [https://github.com/woocommerce/woocommerce-ios/pull/15052]
10+
- [*] Background image upload: Fix issue showing uploaded images while saving is in progress [https://github.com/woocommerce/woocommerce-ios/pull/15107]
911
- [*] Background image upload: Fix missing error notice in iPhones [https://github.com/woocommerce/woocommerce-ios/pull/15117]
12+
- [*] Filters applied in product selector no longer affect the main product list screen. [https://github.com/woocommerce/woocommerce-ios/pull/14764]
1013

1114
21.7
1215
-----

WooCommerce/Classes/POS/Card Present Payments/CardPresentPaymentPreviewService.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@ import struct Yosemite.Order
55

66
#if DEBUG
77

8-
struct CardPresentPaymentPreviewService: CardPresentPaymentFacade {
8+
final class CardPresentPaymentPreviewService: CardPresentPaymentFacade {
99
let paymentEventPublisher: AnyPublisher<CardPresentPaymentEvent, Never> = Just(.idle).eraseToAnyPublisher()
1010

11-
let readerConnectionStatusPublisher: AnyPublisher<CardPresentPaymentReaderConnectionStatus, Never> = Just(.disconnected)
12-
.eraseToAnyPublisher()
11+
@Published var readerConnectionStatus: CardPresentPaymentReaderConnectionStatus = .disconnected
12+
13+
var readerConnectionStatusPublisher: AnyPublisher<CardPresentPaymentReaderConnectionStatus, Never> {
14+
$readerConnectionStatus.eraseToAnyPublisher()
15+
}
1316

1417
func connectReader(using connectionMethod: CardReaderConnectionMethod) async throws -> CardPresentPaymentReaderConnectionResult {
1518
.connected(CardPresentPaymentCardReader(name: "Test reader", batteryLevel: 0.85))

0 commit comments

Comments
 (0)