Skip to content

Commit 7f95212

Browse files
authored
Merge branch 'release/10.1' into merge/10.0.1-into-10.1
2 parents 069fde3 + b1471f6 commit 7f95212

File tree

229 files changed

+3300
-516
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

229 files changed

+3300
-516
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
Contains editorialized release notes. Raw release notes should go into `RELEASE-NOTES.txt`.
33
-->
44

5+
## 10.1
6+
This release has several fixes that makes it easier for you to take payments from the app. We’ve also added a new Help Center FAQ page that makes it easier for you to login to the app.
7+
Please continue to send us feedback – we are listening!
8+
59
## 10.0
610
We made it much easier to find everything about accepting payments in the app. Head on to the Payments section from the Menu! We also fixed an issue where you might be unnecessarily blocked from taking payments.
711
We also made various enhancements to our login flows to help you get started quickly with the app.

Experiments/Experiments/ABTest.swift

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ public enum ABTest: String, CaseIterable {
2020
/// Experiment ref: pbxNRc-1Pp-p2
2121
case linkedProductsPromo = "woocommerceios_product_details_linked_products_banner"
2222

23+
/// A/B test for the login button order on the prologues screen.
24+
/// Experiment ref: pbxNRc-1VA-p2
25+
case loginPrologueButtonOrder = "woocommerceios_login_prologue_button_order"
26+
2327
/// Returns a variation for the given experiment
2428
public var variation: Variation {
2529
ExPlat.shared?.experiment(rawValue) ?? .control
@@ -29,14 +33,30 @@ public enum ABTest: String, CaseIterable {
2933
public extension ABTest {
3034
/// Start the AB Testing platform if any experiment exists
3135
///
32-
static func start() {
33-
guard ABTest.allCases.count > 1 else {
34-
return
35-
}
36-
37-
let experimentNames = ABTest.allCases.filter { $0 != .null }.map { $0.rawValue }
38-
ExPlat.shared?.register(experiments: experimentNames)
36+
static func start() async {
37+
await withCheckedContinuation { continuation in
38+
guard ABTest.allCases.count > 1 else {
39+
return continuation.resume(returning: ())
40+
}
41+
42+
let experimentNames = ABTest.allCases.filter { $0 != .null }.map { $0.rawValue }
43+
ExPlat.shared?.register(experiments: experimentNames)
44+
45+
ExPlat.shared?.refresh {
46+
continuation.resume(returning: ())
47+
}
48+
} as Void
49+
}
50+
}
3951

40-
ExPlat.shared?.refresh()
52+
public extension Variation {
53+
/// Used in an analytics event property value.
54+
var analyticsValue: String {
55+
switch self {
56+
case .control:
57+
return "control"
58+
case .treatment(let string):
59+
return string.map { "treatment: \($0)" } ?? "treatment"
60+
}
4161
}
4262
}

Experiments/Experiments/DefaultFeatureFlagService.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ public struct DefaultFeatureFlagService: FeatureFlagService {
3737
return buildConfig == .localDeveloper || buildConfig == .alpha
3838
case .inPersonPaymentGatewaySelection:
3939
return true
40-
case .unifiedOrderEditing:
41-
return true
4240
case .backgroundProductImageUpload:
4341
return true
4442
case .appleIDAccountDeletion:
@@ -56,7 +54,7 @@ public struct DefaultFeatureFlagService: FeatureFlagService {
5654
case .loginMagicLinkEmphasisM2:
5755
return true
5856
case .promptToEnableCodInIppOnboarding:
59-
return buildConfig == .localDeveloper || buildConfig == .alpha
57+
return true
6058
default:
6159
return true
6260
}

Experiments/Experiments/FeatureFlag.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,6 @@ public enum FeatureFlag: Int {
7474
///
7575
case inPersonPaymentGatewaySelection
7676

77-
/// Enable order editing from the order detailed screen.
78-
///
79-
case unifiedOrderEditing
80-
8177
/// Enable image upload after leaving the product form
8278
///
8379
case backgroundProductImageUpload

Fakes/Fakes/Networking.generated.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,18 @@ extension PaymentGateway {
579579
title: .fake(),
580580
description: .fake(),
581581
enabled: .fake(),
582-
features: .fake()
582+
features: .fake(),
583+
instructions: .fake()
584+
)
585+
}
586+
}
587+
extension PaymentGateway.Setting {
588+
/// Returns a "ready to use" type filled with fake values.
589+
///
590+
public static func fake() -> PaymentGateway.Setting {
591+
.init(
592+
settingID: .fake(),
593+
value: .fake()
583594
)
584595
}
585596
}

Networking/Networking.xcodeproj/project.pbxproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@
7777
02E7FFCB256218F600C53030 /* ShippingLabelRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02E7FFCA256218F600C53030 /* ShippingLabelRemoteTests.swift */; };
7878
02E7FFCF25621C7900C53030 /* shipping-label-print.json in Resources */ = {isa = PBXBuildFile; fileRef = 02E7FFCE25621C7900C53030 /* shipping-label-print.json */; };
7979
02F096C22406691100C0C1D5 /* media-library.json in Resources */ = {isa = PBXBuildFile; fileRef = 02F096C12406691100C0C1D5 /* media-library.json */; };
80+
0313651928AE559D00EEE571 /* PaymentGatewayMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0313651828AE559D00EEE571 /* PaymentGatewayMapper.swift */; };
81+
0313651B28AE60E000EEE571 /* payment-gateway-cod.json in Resources */ = {isa = PBXBuildFile; fileRef = 0313651A28AE60E000EEE571 /* payment-gateway-cod.json */; };
82+
0313651D28AE625300EEE571 /* PaymentGatewayMapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0313651C28AE625300EEE571 /* PaymentGatewayMapperTests.swift */; };
8083
0329CF9B27A82E19008AFF91 /* WCPayCharge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0329CF9A27A82E19008AFF91 /* WCPayCharge.swift */; };
8184
034480C327A42F9100DFACD2 /* order-with-charge.json in Resources */ = {isa = PBXBuildFile; fileRef = 034480C227A42F9100DFACD2 /* order-with-charge.json */; };
8285
0359EA0D27AAC5F80048DE2D /* WCPayChargeStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0359EA0C27AAC5F80048DE2D /* WCPayChargeStatus.swift */; };
@@ -751,6 +754,9 @@
751754
02E7FFCA256218F600C53030 /* ShippingLabelRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingLabelRemoteTests.swift; sourceTree = "<group>"; };
752755
02E7FFCE25621C7900C53030 /* shipping-label-print.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "shipping-label-print.json"; sourceTree = "<group>"; };
753756
02F096C12406691100C0C1D5 /* media-library.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "media-library.json"; sourceTree = "<group>"; };
757+
0313651828AE559D00EEE571 /* PaymentGatewayMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentGatewayMapper.swift; sourceTree = "<group>"; };
758+
0313651A28AE60E000EEE571 /* payment-gateway-cod.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "payment-gateway-cod.json"; sourceTree = "<group>"; };
759+
0313651C28AE625300EEE571 /* PaymentGatewayMapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentGatewayMapperTests.swift; sourceTree = "<group>"; };
754760
0329CF9A27A82E19008AFF91 /* WCPayCharge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WCPayCharge.swift; sourceTree = "<group>"; };
755761
034480C227A42F9100DFACD2 /* order-with-charge.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "order-with-charge.json"; sourceTree = "<group>"; };
756762
0359EA0C27AAC5F80048DE2D /* WCPayChargeStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WCPayChargeStatus.swift; sourceTree = "<group>"; };
@@ -1913,6 +1919,7 @@
19131919
0272E3FA254AABB800436277 /* order-with-line-item-attributes-before-API-support.json */,
19141920
A69FE19C2588D70E0059A96B /* order-with-deleted-refunds.json */,
19151921
261CF1B3255AD6B30090D8D3 /* payment-gateway-list.json */,
1922+
0313651A28AE60E000EEE571 /* payment-gateway-cod.json */,
19161923
261CF2CA255C50010090D8D3 /* payment-gateway-list-half.json */,
19171924
DEC51A96274DD962009F3DF4 /* plugin.json */,
19181925
DEC51A9A274E3206009F3DF4 /* plugin-inactive.json */,
@@ -2077,6 +2084,7 @@
20772084
02C254B825637BA000A04423 /* OrderShippingLabelListMapper.swift */,
20782085
D8FBFF1022D3B3FC006E3336 /* OrderStatsV4Mapper.swift */,
20792086
26731336255ACA850026F7EF /* PaymentGatewayListMapper.swift */,
2087+
0313651828AE559D00EEE571 /* PaymentGatewayMapper.swift */,
20802088
74749B96224134FF005C4CF2 /* ProductMapper.swift */,
20812089
45152810257A81730076B03C /* ProductAttributeMapper.swift */,
20822090
4515280C257A7EEC0076B03C /* ProductAttributeListMapper.swift */,
@@ -2217,6 +2225,7 @@
22172225
74C8F06D20EEC1E700B6EDC9 /* OrderNotesMapperTests.swift */,
22182226
D8FBFF1D22D51F39006E3336 /* OrderStatsMapperV4Tests.swift */,
22192227
262E5AD4255ACD6F000B2416 /* PaymentGatewayListMapperTests.swift */,
2228+
0313651C28AE625300EEE571 /* PaymentGatewayMapperTests.swift */,
22202229
D8A2849925FBB2E70019A84B /* ProductAttributeTermListMapperTests.swift */,
22212230
CE0A0F1C22398D520075ED8D /* ProductListMapperTests.swift */,
22222231
74CF0A8B22414D7800DB993F /* ProductMapperTests.swift */,
@@ -2534,6 +2543,7 @@
25342543
D865CE6B278CA266002C8520 /* stripe-payment-intent-error.json in Resources */,
25352544
CCB2CAA82620ABCC00285CA0 /* shipping-label-create-package-error.json in Resources */,
25362545
B57B1E6C21C94C9F0046E764 /* timeout_error.json in Resources */,
2546+
0313651B28AE60E000EEE571 /* payment-gateway-cod.json in Resources */,
25372547
B5C6FCD620A3768900A4F8E4 /* order.json in Resources */,
25382548
3158FE7426129D9F00E566B9 /* wcpay-account-rejected-other.json in Resources */,
25392549
CC0786C7267BB10700BA9AC1 /* shipping-label-status-success.json in Resources */,
@@ -2877,6 +2887,7 @@
28772887
CC6A1FF5270E042200F6AF4A /* OrderMetaData.swift in Sources */,
28782888
DEC51B02276AFB35009F3DF4 /* SystemStatus+DropinMustUsePlugin.swift in Sources */,
28792889
02C254A4256371B200A04423 /* ShippingLabelSettings.swift in Sources */,
2890+
0313651928AE559D00EEE571 /* PaymentGatewayMapper.swift in Sources */,
28802891
B554FA912180BCFC00C54DFF /* NoteHash.swift in Sources */,
28812892
CE0A0F19223987DF0075ED8D /* ProductListMapper.swift in Sources */,
28822893
021C7BF723863D1800A3BCBD /* Encodable+Serialization.swift in Sources */,
@@ -3067,6 +3078,7 @@
30673078
B505F6D320BEE3A500BB1B69 /* AccountMapperTests.swift in Sources */,
30683079
CC9A254A26442D26005DE56E /* ShippingLabelCreationEligibilityMapperTests.swift in Sources */,
30693080
5726F7342460A8F00031CAAC /* CopiableTests.swift in Sources */,
3081+
0313651D28AE625300EEE571 /* PaymentGatewayMapperTests.swift in Sources */,
30703082
26615479242DA54D00A31661 /* ProductCategoyListMapperTests.swift in Sources */,
30713083
B5C6FCC820A32E4800A4F8E4 /* DateFormatterWooTests.swift in Sources */,
30723084
74C8F06A20EEBC8C00B6EDC9 /* OrderMapperTests.swift in Sources */,

Networking/Networking/Mapper/PaymentGatewayListMapper.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import Foundation
44
///
55
struct PaymentGatewayListMapper: Mapper {
66

7-
/// Site Identifier associated to the shipment trackings that will be parsed.
7+
/// Site Identifier associated to the payment gateways that will be parsed.
88
/// We're injecting this field via `JSONDecoder.userInfo` because the remote endpoints don't
99
/// return the siteID for the payment gateway endpoint
1010
///
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import Foundation
2+
3+
/// Mapper for a `PaymentGateway` JSON object
4+
///
5+
struct PaymentGatewayMapper: Mapper {
6+
7+
/// Site Identifier associated to the payment gateway that will be parsed.
8+
/// We're injecting this field via `JSONDecoder.userInfo` because the remote endpoints don't
9+
/// return the siteID for the payment gateway endpoint
10+
///
11+
let siteID: Int64
12+
13+
/// (Attempts) to convert a dictionary into `PaymentGateway`
14+
///
15+
func map(response: Data) throws -> PaymentGateway {
16+
let decoder = JSONDecoder()
17+
decoder.userInfo = [
18+
.siteID: siteID,
19+
]
20+
return try decoder.decode(PaymentGatewayEnvelope.self, from: response).paymentGateway
21+
}
22+
}
23+
24+
/// PaymentGateway list disposable entity:
25+
/// `Load Payment Gateway` endpoint returns all of the gateway information within a `body` obejcts in the `data` key. This entity
26+
/// allows us to parse all the things with JSONDecoder.
27+
///
28+
private struct PaymentGatewayEnvelope: Decodable {
29+
private enum CodingKeys: String, CodingKey {
30+
case paymentGateway = "data"
31+
}
32+
33+
let paymentGateway: PaymentGateway
34+
}

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

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -665,22 +665,40 @@ extension PaymentGateway {
665665
title: CopiableProp<String> = .copy,
666666
description: CopiableProp<String> = .copy,
667667
enabled: CopiableProp<Bool> = .copy,
668-
features: CopiableProp<[PaymentGateway.Feature]> = .copy
668+
features: CopiableProp<[PaymentGateway.Feature]> = .copy,
669+
instructions: NullableCopiableProp<String> = .copy
669670
) -> PaymentGateway {
670671
let siteID = siteID ?? self.siteID
671672
let gatewayID = gatewayID ?? self.gatewayID
672673
let title = title ?? self.title
673674
let description = description ?? self.description
674675
let enabled = enabled ?? self.enabled
675676
let features = features ?? self.features
677+
let instructions = instructions ?? self.instructions
676678

677679
return PaymentGateway(
678680
siteID: siteID,
679681
gatewayID: gatewayID,
680682
title: title,
681683
description: description,
682684
enabled: enabled,
683-
features: features
685+
features: features,
686+
instructions: instructions
687+
)
688+
}
689+
}
690+
691+
extension PaymentGateway.Setting {
692+
public func copy(
693+
settingID: CopiableProp<String> = .copy,
694+
value: CopiableProp<String> = .copy
695+
) -> PaymentGateway.Setting {
696+
let settingID = settingID ?? self.settingID
697+
let value = value ?? self.value
698+
699+
return PaymentGateway.Setting(
700+
settingID: settingID,
701+
value: value
684702
)
685703
}
686704
}

Networking/Networking/Model/PaymentGateway.swift

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,19 @@ public struct PaymentGateway: Equatable, GeneratedFakeable, GeneratedCopiable {
1313
case custom(raw: String)
1414
}
1515

16+
/// Setting for a payment gateway
17+
///
18+
public struct Setting: Equatable, GeneratedCopiable, GeneratedFakeable {
19+
public let settingID: String
20+
public let value: String
21+
22+
public init(settingID: String,
23+
value: String) {
24+
self.settingID = settingID
25+
self.value = value
26+
}
27+
}
28+
1629
/// Site identifier.
1730
///
1831
public let siteID: Int64
@@ -37,18 +50,29 @@ public struct PaymentGateway: Equatable, GeneratedFakeable, GeneratedCopiable {
3750
///
3851
public let features: [Feature]
3952

40-
public init(siteID: Int64, gatewayID: String, title: String, description: String, enabled: Bool, features: [Feature]) {
53+
/// Instructions shown to the customer after purchase.
54+
///
55+
public let instructions: String?
56+
57+
public init(siteID: Int64,
58+
gatewayID: String,
59+
title: String,
60+
description: String,
61+
enabled: Bool,
62+
features: [Feature],
63+
instructions: String?) {
4164
self.siteID = siteID
4265
self.gatewayID = gatewayID
4366
self.title = title
4467
self.description = description
4568
self.enabled = enabled
4669
self.features = features
70+
self.instructions = instructions
4771
}
4872
}
4973

50-
// MARK: Gateway Decodable
51-
extension PaymentGateway: Decodable {
74+
// MARK: Gateway Codable
75+
extension PaymentGateway: Codable {
5276

5377
public enum DecodingError: Error {
5478
case missingSiteID
@@ -60,7 +84,8 @@ extension PaymentGateway: Decodable {
6084
case description
6185
case enabled
6286
case features = "method_supports"
63-
87+
case instructions
88+
case settings
6489
}
6590

6691
public init(from decoder: Decoder) throws {
@@ -75,17 +100,38 @@ extension PaymentGateway: Decodable {
75100
let enabled = try container.decode(Bool.self, forKey: .enabled)
76101
let features = try container.decode([Feature].self, forKey: .features)
77102

103+
// Settings can have different types for `value`, this implementation only handles `String`
104+
let settings = try? container.decodeIfPresent([String: Setting].self, forKey: .settings)
105+
let instructions = settings?[Setting.Keys.instructions]?.value
106+
78107
self.init(siteID: siteID,
79108
gatewayID: gatewayID,
80109
title: title,
81110
description: description,
82111
enabled: enabled,
83-
features: features)
112+
features: features,
113+
instructions: instructions)
114+
}
115+
116+
public func encode(to encoder: Encoder) throws {
117+
var container = encoder.container(keyedBy: CodingKeys.self)
118+
119+
try container.encode(gatewayID, forKey: .gatewayID)
120+
try container.encode(title, forKey: .title)
121+
try container.encode(description, forKey: .description)
122+
try container.encode(enabled, forKey: .enabled)
123+
try container.encode(features, forKey: .features)
124+
125+
guard let instructions = instructions else {
126+
return
127+
}
128+
let settings = [Setting.Keys.instructions: instructions]
129+
try container.encode(settings, forKey: .settings)
84130
}
85131
}
86132

87-
// MARK: Features Decodable
88-
extension PaymentGateway.Feature: RawRepresentable, Decodable {
133+
// MARK: - Features Decodable
134+
extension PaymentGateway.Feature: RawRepresentable, Codable {
89135

90136
/// Enum containing the 'Known' Feature Keys
91137
///
@@ -116,3 +162,20 @@ extension PaymentGateway.Feature: RawRepresentable, Decodable {
116162
}
117163
}
118164
}
165+
166+
// MARK: - Settings Codable
167+
extension PaymentGateway.Setting: Codable {
168+
/// The known keys, which match `settingID`
169+
///
170+
fileprivate enum Keys {
171+
static let title = "title"
172+
static let instructions = "instructions"
173+
static let enableForMethods = "enable_for_methods"
174+
static let enableForVirtual = "enable_for_virtual"
175+
}
176+
177+
private enum CodingKeys: String, CodingKey {
178+
case settingID = "id"
179+
case value
180+
}
181+
}

0 commit comments

Comments
 (0)