Skip to content

Commit d9ae276

Browse files
committed
Merge branch 'feat/3157-search-products-by-sku-storage' into feat/3157-search-sku
* feat/3157-search-products-by-sku-storage: (167 commits) Update release version in the migration notes. Split CustomerRemoteTests Remove unnecessary CustomerMapper asserts Remove unnecessary default optional values Remove unused dateDecodingStrategy Freeze strings for localization Update metadata strings Update release notes for 10.5 Update Podfile.lock for WordPressAuthenticator Update `WordPressAuthenticator` to stable `3.2.0` Update release notes. Update release notes Release Notes: add new section for next version (10.6) Update draft release notes for 10.5. Bump version number Update CHANGELOG.md Bump version number Revert "Bump version number" Bump version number Revert "Bump version number" ... # Conflicts: # Experiments/Experiments/DefaultFeatureFlagService.swift # Experiments/Experiments/FeatureFlag.swift
2 parents 065b3b6 + 9ecc068 commit d9ae276

File tree

95 files changed

+3315
-931
lines changed

Some content is hidden

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

95 files changed

+3315
-931
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
<!--
22
Contains editorialized release notes. Raw release notes should go into `RELEASE-NOTES.txt`.
33
-->
4+
## 10.5
5+
6+
This release includes a lot of exciting features! It's now possible to duplicate a product from the app. Just tap on the More Menu available inside the Product detail screen. We have also added a new stats widget so now you can view your current day's stats without opening the app. Lastly, due to popular demand, we're bringing back the ability to add/edit customer notes and addresses from the main order screen.
7+
8+
We welcome your feedback on the app, especially the new features we’re working on.
49

510
## 10.4
611

Experiments/Experiments/DefaultFeatureFlagService.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ public struct DefaultFeatureFlagService: FeatureFlagService {
3535
return true
3636
case .searchProductsBySKU:
3737
return buildConfig == .localDeveloper || buildConfig == .alpha
38+
case .orderCreationSearchCustomers:
39+
return buildConfig == .localDeveloper || buildConfig == .alpha
3840
default:
3941
return true
4042
}

Experiments/Experiments/FeatureFlag.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,8 @@ public enum FeatureFlag: Int {
7373
/// Enables searching products by partial SKU for WC version 6.6+.
7474
///
7575
case searchProductsBySKU
76+
77+
/// Enables the Search Customers functionality in the Order Creation screen
78+
///
79+
case orderCreationSearchCustomers
7680
}

Fakes/Fakes/Networking.generated.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,13 +181,40 @@ extension CreateProductVariation {
181181
)
182182
}
183183
}
184+
extension Customer {
185+
/// Returns a "ready to use" type filled with fake values.
186+
///
187+
public static func fake() -> Customer {
188+
.init(
189+
customerID: .fake(),
190+
email: .fake(),
191+
firstName: .fake(),
192+
lastName: .fake(),
193+
billing: .fake(),
194+
shipping: .fake()
195+
)
196+
}
197+
}
184198
extension DotcomError {
185199
/// Returns a "ready to use" type filled with fake values.
186200
///
187201
public static func fake() -> DotcomError {
188202
.empty
189203
}
190204
}
205+
extension DotcomUser {
206+
/// Returns a "ready to use" type filled with fake values.
207+
///
208+
public static func fake() -> DotcomUser {
209+
.init(
210+
id: .fake(),
211+
username: .fake(),
212+
email: .fake(),
213+
displayName: .fake(),
214+
avatar: .fake()
215+
)
216+
}
217+
}
191218
extension InboxAction {
192219
/// Returns a "ready to use" type filled with fake values.
193220
///
@@ -220,6 +247,19 @@ extension InboxNote {
220247
)
221248
}
222249
}
250+
extension JetpackUser {
251+
/// Returns a "ready to use" type filled with fake values.
252+
///
253+
public static func fake() -> JetpackUser {
254+
.init(
255+
isConnected: .fake(),
256+
isPrimary: .fake(),
257+
username: .fake(),
258+
wpcomUser: .fake(),
259+
gravatar: .fake()
260+
)
261+
}
262+
}
223263
extension Leaderboard {
224264
/// Returns a "ready to use" type filled with fake values.
225265
///

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ GEM
165165
xcpretty-travis-formatter (>= 0.0.3)
166166
fastlane-plugin-appcenter (1.11.1)
167167
fastlane-plugin-sentry (1.11.1)
168-
fastlane-plugin-wpmreleasetoolkit (5.4.0)
168+
fastlane-plugin-wpmreleasetoolkit (5.5.0)
169169
activesupport (~> 5)
170170
bigdecimal (~> 1.4)
171171
buildkit (~> 1.5)

Networking/Networking.xcodeproj/project.pbxproj

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,13 @@
324324
57BE08D82409B63800F6DCED /* reviews-missing-avatar-urls.json in Resources */ = {isa = PBXBuildFile; fileRef = 57BE08D72409B63700F6DCED /* reviews-missing-avatar-urls.json */; };
325325
57E8FED3246616AC0057CD68 /* Result+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E8FED2246616AC0057CD68 /* Result+Extensions.swift */; };
326326
6647C0161DAC6AB6570C53A7 /* Pods_Networking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F3F25DC15EC1D7C631169CB5 /* Pods_Networking.framework */; };
327+
68BD37B328D9B8BD00C2A517 /* CustomerRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68BD37B228D9B8BD00C2A517 /* CustomerRemoteTests.swift */; };
327328
68C87B342862D40E00A99054 /* setting-all-except-countries.json in Resources */ = {isa = PBXBuildFile; fileRef = 68C87B332862D40E00A99054 /* setting-all-except-countries.json */; };
329+
68CB800C28D87BC800E169F8 /* Customer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68CB800B28D87BC800E169F8 /* Customer.swift */; };
330+
68CB800E28D8901B00E169F8 /* CustomerMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68CB800D28D8901B00E169F8 /* CustomerMapper.swift */; };
331+
68CB801028D89A0400E169F8 /* CustomerRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68CB800F28D89A0400E169F8 /* CustomerRemote.swift */; };
332+
68CB801428D8A05200E169F8 /* CustomerMapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68CB801328D8A05200E169F8 /* CustomerMapperTests.swift */; };
333+
68CB801628D8A39700E169F8 /* customer.json in Resources */ = {isa = PBXBuildFile; fileRef = 68CB801528D8A39700E169F8 /* customer.json */; };
328334
68FBC5B828928C8C00A05461 /* WooFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 68FBC5B728928C8C00A05461 /* WooFoundation.framework */; };
329335
74002D6A2118B26100A63C19 /* SiteVisitStatsMapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74002D692118B26000A63C19 /* SiteVisitStatsMapperTests.swift */; };
330336
74002D6C2118B88200A63C19 /* SiteVisitStatsRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74002D6B2118B88200A63C19 /* SiteVisitStatsRemoteTests.swift */; };
@@ -1012,7 +1018,13 @@
10121018
5726F7332460A8F00031CAAC /* CopiableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopiableTests.swift; sourceTree = "<group>"; };
10131019
57BE08D72409B63700F6DCED /* reviews-missing-avatar-urls.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "reviews-missing-avatar-urls.json"; sourceTree = "<group>"; };
10141020
57E8FED2246616AC0057CD68 /* Result+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Result+Extensions.swift"; sourceTree = "<group>"; };
1021+
68BD37B228D9B8BD00C2A517 /* CustomerRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomerRemoteTests.swift; sourceTree = "<group>"; };
10151022
68C87B332862D40E00A99054 /* setting-all-except-countries.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "setting-all-except-countries.json"; sourceTree = "<group>"; };
1023+
68CB800B28D87BC800E169F8 /* Customer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Customer.swift; sourceTree = "<group>"; };
1024+
68CB800D28D8901B00E169F8 /* CustomerMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomerMapper.swift; sourceTree = "<group>"; };
1025+
68CB800F28D89A0400E169F8 /* CustomerRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomerRemote.swift; sourceTree = "<group>"; };
1026+
68CB801328D8A05200E169F8 /* CustomerMapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomerMapperTests.swift; sourceTree = "<group>"; };
1027+
68CB801528D8A39700E169F8 /* customer.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = customer.json; sourceTree = "<group>"; };
10161028
68FBC5B728928C8C00A05461 /* WooFoundation.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = WooFoundation.framework; sourceTree = BUILT_PRODUCTS_DIR; };
10171029
69314EDE650855CAF927057E /* Pods_NetworkingTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_NetworkingTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
10181030
74002D692118B26000A63C19 /* SiteVisitStatsMapperTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SiteVisitStatsMapperTests.swift; sourceTree = "<group>"; };
@@ -1618,6 +1630,7 @@
16181630
FE28F6EB268436C9004465C7 /* UserRemoteTests.swift */,
16191631
077F39D926A58ED700ABEADC /* SystemStatusRemoteTests.swift */,
16201632
DE34051E28BDFB0B00CF0D97 /* JetpackConnectionRemoteTests.swift */,
1633+
68BD37B228D9B8BD00C2A517 /* CustomerRemoteTests.swift */,
16211634
);
16221635
path = Remote;
16231636
sourceTree = "<group>";
@@ -1750,6 +1763,7 @@
17501763
FE28F6E5268429B6004465C7 /* UserRemote.swift */,
17511764
077F39D526A58E4500ABEADC /* SystemStatusRemote.swift */,
17521765
AEF94584272974F2001DCCFB /* TelemetryRemote.swift */,
1766+
68CB800F28D89A0400E169F8 /* CustomerRemote.swift */,
17531767
);
17541768
path = Remote;
17551769
sourceTree = "<group>";
@@ -1857,6 +1871,7 @@
18571871
FE28F6E126840DED004465C7 /* User.swift */,
18581872
DE50295828C5BD0200551736 /* JetpackUser.swift */,
18591873
DE50295A28C5F99700551736 /* DotcomUser.swift */,
1874+
68CB800B28D87BC800E169F8 /* Customer.swift */,
18601875
);
18611876
path = Model;
18621877
sourceTree = "<group>";
@@ -2092,6 +2107,7 @@
20922107
4513382727A96DE700AE5E78 /* inbox-note.json */,
20932108
0205021B27C86B9700FB1C6B /* inbox-note-without-isRead.json */,
20942109
68C87B332862D40E00A99054 /* setting-all-except-countries.json */,
2110+
68CB801528D8A39700E169F8 /* customer.json */,
20952111
);
20962112
path = Responses;
20972113
sourceTree = "<group>";
@@ -2184,6 +2200,7 @@
21842200
02C112772742862600F4F0B4 /* WordPressSiteSettingsMapper.swift */,
21852201
0359EA1C27AADE000048DE2D /* WCPayChargeMapper.swift */,
21862202
DE34051828BDEE6A00CF0D97 /* JetpackConnectionURLMapper.swift */,
2203+
68CB800D28D8901B00E169F8 /* CustomerMapper.swift */,
21872204
);
21882205
path = Mapper;
21892206
sourceTree = "<group>";
@@ -2306,6 +2323,7 @@
23062323
DE34051C28BDF1C900CF0D97 /* JetpackConnectionURLMapperTests.swift */,
23072324
DE50296428C60A8000551736 /* JetpackUserMapperTests.swift */,
23082325
0359EA1E27AAE4680048DE2D /* WCPayChargeMapperTests.swift */,
2326+
68CB801328D8A05200E169F8 /* CustomerMapperTests.swift */,
23092327
);
23102328
path = Mapper;
23112329
sourceTree = "<group>";
@@ -2688,6 +2706,7 @@
26882706
7497376A2141F2BE0008C490 /* top-performers-week-alt.json in Resources */,
26892707
D865CE61278CA1AE002C8520 /* stripe-payment-intent-processing.json in Resources */,
26902708
743E84F222172D0A00FAC9D7 /* shipment_tracking_plugin_not_active.json in Resources */,
2709+
68CB801628D8A39700E169F8 /* customer.json in Resources */,
26912710
451A97DE260B59870059D135 /* shipping-label-packages-success.json in Resources */,
26922711
31D27C8F2602B553002EDB1D /* plugins.json in Resources */,
26932712
261CF1B4255AD6B30090D8D3 /* payment-gateway-list.json in Resources */,
@@ -2986,6 +3005,7 @@
29863005
B518662220A097C200037A38 /* Network.swift in Sources */,
29873006
B572F69A21AC475C003EEFF0 /* DevicesRemote.swift in Sources */,
29883007
3192F220260D33BB0067FEF9 /* WCPayAccount.swift in Sources */,
3008+
68CB800E28D8901B00E169F8 /* CustomerMapper.swift in Sources */,
29893009
45CCFCE227A2C9BF0012E8CB /* InboxNote.swift in Sources */,
29903010
311D412C2783BF7400052F64 /* StripeAccount.swift in Sources */,
29913011
B518662420A099BF00037A38 /* AlamofireNetwork.swift in Sources */,
@@ -3034,6 +3054,7 @@
30343054
020D07BE23D8570800FD9580 /* MediaListMapper.swift in Sources */,
30353055
0359EA1327AAC6D00048DE2D /* WCPayCardPaymentDetails.swift in Sources */,
30363056
CCB2CA9E262091CB00285CA0 /* SuccessDataResultMapper.swift in Sources */,
3057+
68CB801028D89A0400E169F8 /* CustomerRemote.swift in Sources */,
30373058
DE50295B28C5F99700551736 /* DotcomUser.swift in Sources */,
30383059
74C8F06820EEB7BD00B6EDC9 /* OrderNotesMapper.swift in Sources */,
30393060
24F98C582502EA8800F49B68 /* FeatureFlagMapper.swift in Sources */,
@@ -3043,6 +3064,7 @@
30433064
74046E1D217A6989007DD7BF /* SiteSetting.swift in Sources */,
30443065
B5BB1D1020A237FB00112D92 /* Address.swift in Sources */,
30453066
CE43066A23465F340073CBFF /* Refund.swift in Sources */,
3067+
68CB800C28D87BC800E169F8 /* Customer.swift in Sources */,
30463068
DE50295D28C6068B00551736 /* JetpackUserMapper.swift in Sources */,
30473069
B524194121AC60A700D6FC0A /* DotcomDevice.swift in Sources */,
30483070
D8EDFE2225EE88C9003D2213 /* ReaderConnectionToken.swift in Sources */,
@@ -3128,6 +3150,7 @@
31283150
CEC4BF8F234E382F008D9195 /* RefundMapperTests.swift in Sources */,
31293151
24F98C5E2502EDCF00F49B68 /* BundleWooTests.swift in Sources */,
31303152
74AB0ACA21948CE4008220CD /* CommentResultMapperTests.swift in Sources */,
3153+
68CB801428D8A05200E169F8 /* CustomerMapperTests.swift in Sources */,
31313154
02698CF824C183A5005337C4 /* ProductVariationListMapperTests.swift in Sources */,
31323155
B524194921AC659500D6FC0A /* DevicesRemoteTests.swift in Sources */,
31333156
2685C0DA263B551300D9EE97 /* AddOnGroupMapperTests.swift in Sources */,
@@ -3202,6 +3225,7 @@
32023225
45CCFCE827A2E5020012E8CB /* InboxNoteListMapperTests.swift in Sources */,
32033226
74002D6C2118B88200A63C19 /* SiteVisitStatsRemoteTests.swift in Sources */,
32043227
0212683524C046CB00F8A892 /* MockNetwork+Path.swift in Sources */,
3228+
68BD37B328D9B8BD00C2A517 /* CustomerRemoteTests.swift in Sources */,
32053229
B554FA932180C17200C54DFF /* NoteHashListMapperTests.swift in Sources */,
32063230
CC07866526790B1100BA9AC1 /* ShippingLabelPurchaseMapperTests.swift in Sources */,
32073231
74002D6A2118B26100A63C19 /* SiteVisitStatsMapperTests.swift in Sources */,
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import Foundation
2+
3+
/// Mapper: Customer
4+
///
5+
struct CustomerMapper: Mapper {
6+
/// We're injecting this field by copying it in after parsing responses, because `siteID` is not returned in any of the Customer endpoints.
7+
///
8+
let siteID: Int64
9+
10+
/// (Attempts) to convert a dictionary into a `Customer` entity
11+
///
12+
func map(response: Data) throws -> Customer {
13+
let decoder = JSONDecoder()
14+
decoder.userInfo = [.siteID: siteID]
15+
let customer = try decoder.decode(CustomerEnvelope.self, from: response).customer
16+
return customer
17+
}
18+
}
19+
20+
private struct CustomerEnvelope: Decodable {
21+
let customer: Customer
22+
23+
private enum CodingKeys: String, CodingKey {
24+
case customer = "data"
25+
}
26+
}

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,33 @@ extension CouponReport {
169169
}
170170
}
171171

172+
extension Customer {
173+
func copy(
174+
customerID: CopiableProp<Int64> = .copy,
175+
email: CopiableProp<String> = .copy,
176+
firstName: NullableCopiableProp<String> = .copy,
177+
lastName: NullableCopiableProp<String> = .copy,
178+
billing: NullableCopiableProp<Address> = .copy,
179+
shipping: NullableCopiableProp<Address> = .copy
180+
) -> Customer {
181+
let customerID = customerID ?? self.customerID
182+
let email = email ?? self.email
183+
let firstName = firstName ?? self.firstName
184+
let lastName = lastName ?? self.lastName
185+
let billing = billing ?? self.billing
186+
let shipping = shipping ?? self.shipping
187+
188+
return Customer(
189+
customerID: customerID,
190+
email: email,
191+
firstName: firstName,
192+
lastName: lastName,
193+
billing: billing,
194+
shipping: shipping
195+
)
196+
}
197+
}
198+
172199
extension DotcomUser {
173200
public func copy(
174201
id: CopiableProp<Int64> = .copy,
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import Foundation
2+
import Codegen
3+
4+
/// Represents a Customer entity:
5+
/// https://woocommerce.github.io/woocommerce-rest-api-docs/#customer-properties
6+
///
7+
public struct Customer: Codable, GeneratedCopiable, GeneratedFakeable {
8+
9+
/// Unique identifier for the customer
10+
public let customerID: Int64
11+
12+
/// The email address for the customer
13+
public let email: String
14+
15+
/// Customer first name
16+
public let firstName: String?
17+
18+
/// Customer last name
19+
public let lastName: String?
20+
21+
/// List of billing address data
22+
public let billing: Address?
23+
24+
/// List of shipping address data
25+
public let shipping: Address?
26+
27+
/// Customer struct initializer
28+
///
29+
public init(customerID: Int64,
30+
email: String,
31+
firstName: String?,
32+
lastName: String?,
33+
billing: Address?,
34+
shipping: Address?) {
35+
self.customerID = customerID
36+
self.email = email
37+
self.firstName = firstName
38+
self.lastName = lastName
39+
self.billing = billing
40+
self.shipping = shipping
41+
}
42+
43+
/// Public initializer for the Customer
44+
///
45+
public init(from decoder: Decoder) throws {
46+
let container = try decoder.container(keyedBy: CodingKeys.self)
47+
48+
let customerID = try container.decode(Int64.self, forKey: .customerID)
49+
let email = try container.decode(String.self, forKey: .email)
50+
let firstName = try container.decodeIfPresent(String.self, forKey: .firstName)
51+
let lastName = try container.decodeIfPresent(String.self, forKey: .lastName)
52+
let billing = try? container.decode(Address.self, forKey: .billing)
53+
let shipping = try? container.decode(Address.self, forKey: .shipping)
54+
55+
self.init(customerID: customerID,
56+
email: email,
57+
firstName: firstName,
58+
lastName: lastName,
59+
billing: billing,
60+
shipping: shipping
61+
)
62+
}
63+
}
64+
65+
/// Defines all of the Customer CodingKeys
66+
///
67+
extension Customer {
68+
enum CodingKeys: String, CodingKey {
69+
case customerID = "id"
70+
case email
71+
case firstName = "first_name"
72+
case lastName = "last_name"
73+
case billing
74+
case shipping
75+
}
76+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import Foundation
2+
3+
public class CustomerRemote: Remote {
4+
/// Retrieves a `Customer`
5+
///
6+
/// - Parameters:
7+
/// - customerID: ID of the customer that will be retrieved
8+
/// - siteID: Site for which we'll fetch the customer.
9+
/// - completion: Closure to be executed upon completion.
10+
///
11+
func retrieveCustomer(for siteID: Int64, with customerID: Int64, completion: @escaping (Result<Customer, Error>) -> Void) {
12+
let path = "/customers/\(customerID)"
13+
let request = JetpackRequest(wooApiVersion: .mark3,
14+
method: .get,
15+
siteID: siteID,
16+
path: path,
17+
parameters: nil
18+
)
19+
20+
let mapper = CustomerMapper(siteID: siteID)
21+
enqueue(request, mapper: mapper, completion: completion)
22+
}
23+
}

0 commit comments

Comments
 (0)