From 7a8548ba7ad1c37469bd5235566ac748ebe7bb9b Mon Sep 17 00:00:00 2001
From: Povilas Staskus <4062343+staskus@users.noreply.github.com>
Date: Thu, 28 Aug 2025 23:59:31 +0300
Subject: [PATCH 01/12] Add userID to Customer entity
Customer and WCAnalyticsCustomer are used in the app together to facilitate order creation and customer management.
customerID on Customer object was sometimes overwritten by userID from WCAnalyticsCustomer making it ambiguous which one is used at what time.
---
.../Model/Customer+CoreDataProperties.swift | 1 +
Modules/Sources/Storage/Model/MIGRATIONS.md | 4 +
.../.xccurrentversion | 2 +-
.../Model 125.xcdatamodel/contents | 1105 +++++++++++++++++
4 files changed, 1111 insertions(+), 1 deletion(-)
create mode 100644 Modules/Sources/Storage/Resources/WooCommerce.xcdatamodeld/Model 125.xcdatamodel/contents
diff --git a/Modules/Sources/Storage/Model/Customer+CoreDataProperties.swift b/Modules/Sources/Storage/Model/Customer+CoreDataProperties.swift
index cacfaea1ce2..b2a8f049213 100644
--- a/Modules/Sources/Storage/Model/Customer+CoreDataProperties.swift
+++ b/Modules/Sources/Storage/Model/Customer+CoreDataProperties.swift
@@ -20,6 +20,7 @@ extension Customer {
@NSManaged public var billingPostcode: String?
@NSManaged public var billingState: String?
@NSManaged public var customerID: Int64
+ @NSManaged public var userID: Int64
@NSManaged public var email: String?
@NSManaged public var username: String?
@NSManaged public var firstName: String?
diff --git a/Modules/Sources/Storage/Model/MIGRATIONS.md b/Modules/Sources/Storage/Model/MIGRATIONS.md
index 922e07d28d8..9b7b31147f7 100644
--- a/Modules/Sources/Storage/Model/MIGRATIONS.md
+++ b/Modules/Sources/Storage/Model/MIGRATIONS.md
@@ -2,6 +2,10 @@
This file documents changes in the WCiOS Storage data model. Please explain any changes to the data model as well as any custom migrations.
+## Model 125 (Release 23.2.0.0)
+- @povilasstaskus 2025-08-28
+ - Added `userID` attribute to `Customer` entity to link customers with WordPress user accounts.
+
## Model 124 (Release 22.9.0.0)
- @itsmeichigo 2025-07-11
- Added `WooShippingShipment` entity.
diff --git a/Modules/Sources/Storage/Resources/WooCommerce.xcdatamodeld/.xccurrentversion b/Modules/Sources/Storage/Resources/WooCommerce.xcdatamodeld/.xccurrentversion
index 3bd45fad8e3..a3ea46178c4 100644
--- a/Modules/Sources/Storage/Resources/WooCommerce.xcdatamodeld/.xccurrentversion
+++ b/Modules/Sources/Storage/Resources/WooCommerce.xcdatamodeld/.xccurrentversion
@@ -3,6 +3,6 @@
_XCCurrentVersionName
- Model 124.xcdatamodel
+ Model 125.xcdatamodel
diff --git a/Modules/Sources/Storage/Resources/WooCommerce.xcdatamodeld/Model 125.xcdatamodel/contents b/Modules/Sources/Storage/Resources/WooCommerce.xcdatamodeld/Model 125.xcdatamodel/contents
new file mode 100644
index 00000000000..8c180ad10e7
--- /dev/null
+++ b/Modules/Sources/Storage/Resources/WooCommerce.xcdatamodeld/Model 125.xcdatamodel/contents
@@ -0,0 +1,1105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
From 679dd04d5ec0aa40c1aa88070ec750eb70268423 Mon Sep 17 00:00:00 2001
From: Povilas Staskus <4062343+staskus@users.noreply.github.com>
Date: Thu, 28 Aug 2025 23:59:44 +0300
Subject: [PATCH 02/12] Update generated fakes
---
Modules/Sources/Fakes/Networking.generated.swift | 1 +
.../Networking/Model/Copiable/Models+Copiable.generated.swift | 3 +++
2 files changed, 4 insertions(+)
diff --git a/Modules/Sources/Fakes/Networking.generated.swift b/Modules/Sources/Fakes/Networking.generated.swift
index 873d7361fcc..8976c1cb80c 100644
--- a/Modules/Sources/Fakes/Networking.generated.swift
+++ b/Modules/Sources/Fakes/Networking.generated.swift
@@ -442,6 +442,7 @@ extension Networking.Customer {
public static func fake() -> Networking.Customer {
.init(
siteID: .fake(),
+ userID: .fake(),
customerID: .fake(),
email: .fake(),
username: .fake(),
diff --git a/Modules/Sources/Networking/Model/Copiable/Models+Copiable.generated.swift b/Modules/Sources/Networking/Model/Copiable/Models+Copiable.generated.swift
index b41103490e5..db0109b0200 100644
--- a/Modules/Sources/Networking/Model/Copiable/Models+Copiable.generated.swift
+++ b/Modules/Sources/Networking/Model/Copiable/Models+Copiable.generated.swift
@@ -637,6 +637,7 @@ extension Networking.CreateProductVariation {
extension Networking.Customer {
public func copy(
siteID: CopiableProp = .copy,
+ userID: CopiableProp = .copy,
customerID: CopiableProp = .copy,
email: CopiableProp = .copy,
username: NullableCopiableProp = .copy,
@@ -646,6 +647,7 @@ extension Networking.Customer {
shipping: NullableCopiableProp = .copy
) -> Networking.Customer {
let siteID = siteID ?? self.siteID
+ let userID = userID ?? self.userID
let customerID = customerID ?? self.customerID
let email = email ?? self.email
let username = username ?? self.username
@@ -656,6 +658,7 @@ extension Networking.Customer {
return Networking.Customer(
siteID: siteID,
+ userID: userID,
customerID: customerID,
email: email,
username: username,
From 28b103e11b8d11e87bae47935f7c3857b8c20c95 Mon Sep 17 00:00:00 2001
From: Povilas Staskus <4062343+staskus@users.noreply.github.com>
Date: Fri, 29 Aug 2025 00:00:49 +0300
Subject: [PATCH 03/12] Map both customerID and userID when updating
Storage.Customer
When updating Storage.Customer from WCAnalyticsCustomer map both customerID and userID so they could be both used directly and unambiguously when needed
---
.../Customer+ReadOnlyConvertible.swift | 26 ++++++++++++++++---
1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/Modules/Sources/Yosemite/Model/Storage/Customer+ReadOnlyConvertible.swift b/Modules/Sources/Yosemite/Model/Storage/Customer+ReadOnlyConvertible.swift
index f88718649bc..018c57df06a 100644
--- a/Modules/Sources/Yosemite/Model/Storage/Customer+ReadOnlyConvertible.swift
+++ b/Modules/Sources/Yosemite/Model/Storage/Customer+ReadOnlyConvertible.swift
@@ -1,6 +1,11 @@
import Foundation
import Storage
+/// Storage.Customer is an aggregate object that combines data from multiple sources:
+/// 1. WCAnalyticsCustomer (analytics data) - contains customerID and userID (0 if WordPress user is not registered)
+/// 2. Networking.Customer (WordPress user data) - contains userId (WordPress user ID)
+///
+///
public protocol StorageCustomerConvertible {
var loadingID: Int64 { get }
}
@@ -10,7 +15,7 @@ extension Yosemite.Customer: StorageCustomerConvertible {
}
extension Yosemite.WCAnalyticsCustomer: StorageCustomerConvertible {
- public var loadingID: Int64 { userID }
+ public var loadingID: Int64 { customerID }
}
// MARK: - Storage.Customer: ReadOnlyConvertible
@@ -28,9 +33,11 @@ extension Storage.Customer: ReadOnlyConvertible {
}
/// Updates the `Storage.Customer` from the ReadOnly representation (`Networking.Customer`)
+ /// This is called when we have WordPress user customer data
///
public func update(with customer: Yosemite.Customer) {
- customerID = customer.customerID
+ // WordPress customers are registered users, so userID equals userId
+ userID = customer.userID
siteID = customer.siteID
email = customer.email
firstName = customer.firstName
@@ -65,7 +72,9 @@ extension Storage.Customer: ReadOnlyConvertible {
/// Updates the `Storage.Customer` from the ReadOnly representation (`Yosemite.WCAnalyticsCustomer`)
///
public func update(with customer: Yosemite.WCAnalyticsCustomer) {
- customerID = customer.userID
+ customerID = customer.customerID
+ // Set userID to link with WordPress user account (if registered)
+ userID = customer.userID
siteID = customer.siteID
email = customer.email
username = customer.username
@@ -80,10 +89,18 @@ extension Storage.Customer: ReadOnlyConvertible {
shippingFirstName = firstName
shippingLastName = lastName
shippingEmail = email
+ shippingCity = customer.city
+ shippingState = customer.region
+ shippingPostcode = customer.postcode
+ shippingCountry = customer.country
billingFirstName = firstName
billingLastName = lastName
billingEmail = email
+ billingCity = customer.city
+ billingState = customer.region
+ billingPostcode = customer.postcode
+ billingCountry = customer.country
}
/// Returns a ReadOnly (`Networking.Customer`) version of the `Storage.Customer`
@@ -91,7 +108,8 @@ extension Storage.Customer: ReadOnlyConvertible {
public func toReadOnly() -> Yosemite.Customer {
return Customer(
siteID: siteID,
- customerID: customerID,
+ userID: userID, // WordPress user ID (if registered)
+ customerID: customerID, // Analytics customer ID
email: email ?? "",
username: username ?? "",
firstName: firstName ?? "",
From 1f263e6044c9fd45b895f7467eeeec5906ea086c Mon Sep 17 00:00:00 2001
From: Povilas Staskus <4062343+staskus@users.noreply.github.com>
Date: Fri, 29 Aug 2025 00:01:54 +0300
Subject: [PATCH 04/12] Update Networking.Customer model to use both userID and
customerID
Networking.Customer is used for both WCAnalyticsCustomer and Customer use cases. Since WCAnalyticsCustomer contains both userID and customerID, we need Customer to contain both so data wouldn't be lost in the conversion
---
.../Sources/Networking/Model/Customer.swift | 27 ++++++++++++++-----
1 file changed, 21 insertions(+), 6 deletions(-)
diff --git a/Modules/Sources/Networking/Model/Customer.swift b/Modules/Sources/Networking/Model/Customer.swift
index 059c8ed3adc..dedc6e5113d 100644
--- a/Modules/Sources/Networking/Model/Customer.swift
+++ b/Modules/Sources/Networking/Model/Customer.swift
@@ -4,11 +4,24 @@ import Codegen
/// Represents a Customer entity:
/// https://woocommerce.github.io/woocommerce-rest-api-docs/#customer-properties
///
+/// This model is used in TWO different contexts:
+/// 1. When fetching from `/wc/v3/customers/{id}` endpoint:
+/// - `userID` = WordPress user ID (mapped from API "id" field)
+/// - `customerID` = 0 (not available from this endpoint)
+/// 2. When converting from Storage.Customer via toReadOnly():
+/// - `userID` = WordPress user ID (if registered)
+/// - `customerID` = Analytics customer ID (from WCAnalyticsCustomer)
+///
public struct Customer: Codable, GeneratedCopiable, GeneratedFakeable, Equatable {
/// The siteID for the customer
public let siteID: Int64
- /// Unique identifier for the customer
+ /// WordPress user ID (mapped from API "id" field)
+ /// This is the WordPress user account identifier, not the analytics customer ID
+ public let userID: Int64
+
+ /// Analytics customer ID (only set when converting from Storage.Customer taking value from WCAnalyticsCustomer)
+ /// This field is not mapped to any API response
public let customerID: Int64
/// The email address for the customer
@@ -31,13 +44,14 @@ public struct Customer: Codable, GeneratedCopiable, GeneratedFakeable, Equatable
/// Computed property to check if the customer is a guest
public var isGuest: Bool {
- customerID == 0
+ userID == 0
}
/// Customer struct initializer
///
public init(siteID: Int64,
- customerID: Int64,
+ userID: Int64,
+ customerID: Int64 = 0,
email: String,
username: String?,
firstName: String?,
@@ -45,6 +59,7 @@ public struct Customer: Codable, GeneratedCopiable, GeneratedFakeable, Equatable
billing: Address?,
shipping: Address?) {
self.siteID = siteID
+ self.userID = userID
self.customerID = customerID
self.email = email
self.username = username
@@ -63,7 +78,7 @@ public struct Customer: Codable, GeneratedCopiable, GeneratedFakeable, Equatable
let container = try decoder.container(keyedBy: CodingKeys.self)
- let customerID = try container.decode(Int64.self, forKey: .customerID)
+ let userID = try container.decode(Int64.self, forKey: .userID)
let email = try container.decode(String.self, forKey: .email)
let username = try container.decode(String.self, forKey: .username)
let firstName = try container.decodeIfPresent(String.self, forKey: .firstName)
@@ -72,7 +87,7 @@ public struct Customer: Codable, GeneratedCopiable, GeneratedFakeable, Equatable
let shipping = try? container.decode(Address.self, forKey: .shipping)
self.init(siteID: siteID,
- customerID: customerID,
+ userID: userID,
email: email,
username: username,
firstName: firstName,
@@ -87,7 +102,7 @@ public struct Customer: Codable, GeneratedCopiable, GeneratedFakeable, Equatable
///
extension Customer {
enum CodingKeys: String, CodingKey {
- case customerID = "id"
+ case userID = "id"
case email
case username
case firstName = "first_name"
From 4327afa64fc4c9dd7c79c940851928e650cf6252 Mon Sep 17 00:00:00 2001
From: Povilas Staskus <4062343+staskus@users.noreply.github.com>
Date: Fri, 29 Aug 2025 00:02:25 +0300
Subject: [PATCH 05/12] Explicitly set customer.userID for Order CustomerFilter
Customer filter in orders doesn't work for non-registered users (that don't have userID set)
---
Modules/Sources/Yosemite/Model/Orders/CustomerFilter.swift | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Modules/Sources/Yosemite/Model/Orders/CustomerFilter.swift b/Modules/Sources/Yosemite/Model/Orders/CustomerFilter.swift
index 98332f1bd39..dd24611a75b 100644
--- a/Modules/Sources/Yosemite/Model/Orders/CustomerFilter.swift
+++ b/Modules/Sources/Yosemite/Model/Orders/CustomerFilter.swift
@@ -10,7 +10,7 @@ public struct CustomerFilter: Codable, Hashable {
public let username: String?
public init(customer: Customer) {
- self.id = customer.customerID
+ self.id = customer.userID
self.firstName = customer.firstName
self.lastName = customer.lastName
self.email = customer.email
From 867dfec1b8807a22a7f8cbd94e7b501c42d9bada Mon Sep 17 00:00:00 2001
From: Povilas Staskus <4062343+staskus@users.noreply.github.com>
Date: Fri, 29 Aug 2025 00:02:30 +0300
Subject: [PATCH 06/12] Add migration tests
---
.../CoreData/MigrationTests.swift | 72 ++++++++++++++++---
1 file changed, 64 insertions(+), 8 deletions(-)
diff --git a/Modules/Tests/StorageTests/CoreData/MigrationTests.swift b/Modules/Tests/StorageTests/CoreData/MigrationTests.swift
index 46295f3db18..640079c80b9 100644
--- a/Modules/Tests/StorageTests/CoreData/MigrationTests.swift
+++ b/Modules/Tests/StorageTests/CoreData/MigrationTests.swift
@@ -3468,6 +3468,70 @@ final class MigrationTests: XCTestCase {
let urlValue = migratedObject.value(forKey: "addPaymentMethodURL") as? String
XCTAssertEqual(urlValue, "https://example.com")
}
+
+ func test_migrating_from_124_to_125_adds_userID_to_Customer_entity() throws {
+ // Given
+ let sourceContainer = try startPersistentContainer("Model 124")
+ let sourceContext = sourceContainer.viewContext
+
+ // Create a customer in the source model (Model 124)
+ let object = sourceContext.insert(entityName: "Customer", properties: [
+ "siteID": 123,
+ "customerID": 456,
+ "email": "test@example.com",
+ "firstName": "John",
+ "lastName": "Doe",
+ "username": "johndoe"
+ ])
+
+ try sourceContext.save()
+
+ XCTAssertEqual(try sourceContext.count(entityName: "Customer"), 1)
+
+ // Verify the customer exists and has the expected properties
+ let sourceCustomer = try XCTUnwrap(sourceContext.allObjects(entityName: "Customer").first)
+ XCTAssertEqual(sourceCustomer.value(forKey: "siteID") as? Int64, 123)
+ XCTAssertEqual(sourceCustomer.value(forKey: "customerID") as? Int64, 456)
+ XCTAssertEqual(sourceCustomer.value(forKey: "email") as? String, "test@example.com")
+
+ // Verify userID field doesn't exist in Model 124
+ XCTAssertNil(object.entity.attributesByName["userID"], "Precondition. Attribute does not exist.")
+
+
+ // When
+ let targetContainer = try migrate(sourceContainer, to: "Model 125")
+
+ // Then
+ let targetContext = targetContainer.viewContext
+
+ XCTAssertEqual(try targetContext.count(entityName: "Customer"), 1)
+
+ let migratedCustomer = try XCTUnwrap(targetContext.allObjects(entityName: "Customer").first)
+
+ // Verify existing fields are preserved
+ XCTAssertEqual(migratedCustomer.value(forKey: "siteID") as? Int64, 123)
+ XCTAssertEqual(migratedCustomer.value(forKey: "customerID") as? Int64, 456)
+ XCTAssertEqual(migratedCustomer.value(forKey: "email") as? String, "test@example.com")
+ XCTAssertEqual(migratedCustomer.value(forKey: "firstName") as? String, "John")
+ XCTAssertEqual(migratedCustomer.value(forKey: "lastName") as? String, "Doe")
+ XCTAssertEqual(migratedCustomer.value(forKey: "username") as? String, "johndoe")
+
+ // Verify new userID field exists and has default value
+ XCTAssertEqual(migratedCustomer.value(forKey: "userID") as? Int64, 0)
+
+ // Verify we can set and retrieve the new userID field
+ migratedCustomer.setValue(789, forKey: "userID")
+ XCTAssertEqual(migratedCustomer.value(forKey: "userID") as? Int64, 789)
+ }
+
+
+ @discardableResult
+ func insertWooShippingOriginAddress(to context: NSManagedObjectContext) -> NSManagedObject {
+ context.insert(entityName: "WooShippingOriginAddress", properties: [
+ "siteID": 1,
+ "id": "test-address"
+ ])
+ }
}
// MARK: - Persistent Store Setup and Migrations
@@ -4384,12 +4448,4 @@ private extension MigrationTests {
"subItems": ["sub_1", "sub_2"]
])
}
-
- @discardableResult
- func insertWooShippingOriginAddress(to context: NSManagedObjectContext) -> NSManagedObject {
- context.insert(entityName: "WooShippingOriginAddress", properties: [
- "siteID": 1,
- "id": "test-address"
- ])
- }
}
From 3d4cb10168a31c56fda8a749a785cb696a4a6bb8 Mon Sep 17 00:00:00 2001
From: Povilas Staskus <4062343+staskus@users.noreply.github.com>
Date: Fri, 29 Aug 2025 00:02:49 +0300
Subject: [PATCH 07/12] Explicitly use userID and customerID where needed in
CustomerDetailViewModel
---
.../Customers/CustomerDetailViewModel.swift | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/WooCommerce/Classes/ViewRelated/Customers/CustomerDetailViewModel.swift b/WooCommerce/Classes/ViewRelated/Customers/CustomerDetailViewModel.swift
index 4d44ebba752..f09c75e0ba4 100644
--- a/WooCommerce/Classes/ViewRelated/Customers/CustomerDetailViewModel.swift
+++ b/WooCommerce/Classes/ViewRelated/Customers/CustomerDetailViewModel.swift
@@ -9,6 +9,7 @@ final class CustomerDetailViewModel: ObservableObject {
private let storageManager: StorageManagerType
private let siteID: Int64
private let customerID: Int64
+ private let userID: Int64
/// Customer name
let name: String
@@ -101,6 +102,7 @@ final class CustomerDetailViewModel: ObservableObject {
init(siteID: Int64,
customerID: Int64,
+ userID: Int64,
name: String?,
dateLastActive: String?,
email: String?,
@@ -119,6 +121,7 @@ final class CustomerDetailViewModel: ObservableObject {
self.storageManager = storageManager
self.siteID = siteID
self.customerID = customerID
+ self.userID = userID
self.name = name ?? Localization.guestName
self.dateLastActive = dateLastActive
self.email = email
@@ -141,7 +144,8 @@ final class CustomerDetailViewModel: ObservableObject {
storageManager: StorageManagerType = ServiceLocator.storageManager) {
let currencyFormatter = CurrencyFormatter(currencySettings: currencySettings)
self.init(siteID: customer.siteID,
- customerID: customer.userID,
+ customerID: customer.customerID,
+ userID: customer.userID,
name: customer.name?.nullifyIfEmptyOrWhitespace(),
dateLastActive: customer.dateLastActive.map { DateFormatter.mediumLengthLocalizedDateFormatter.string(from: $0) },
email: customer.email?.nullifyIfEmptyOrWhitespace(),
@@ -309,13 +313,13 @@ extension CustomerDetailViewModel {
///
func syncCustomerAddressData() {
// Only try to sync the address data for registered customers
- guard customerID != 0 else {
+ guard userID != 0 else {
return
}
// Don't show loading state if we already have customer billing or shipping data to display
updateStateIfNeeded(to: .loading)
- let action = CustomerAction.retrieveCustomer(siteID: siteID, customerID: customerID) { [weak self] result in
+ let action = CustomerAction.retrieveCustomer(siteID: siteID, customerID: userID) { [weak self] result in
guard let self else { return }
switch result {
case .success:
From 4b1415671bee0d61ebafa36dcb20ddf591569747 Mon Sep 17 00:00:00 2001
From: Povilas Staskus <4062343+staskus@users.noreply.github.com>
Date: Fri, 29 Aug 2025 00:03:07 +0300
Subject: [PATCH 08/12] Explicitly use userID and customerID where needed in
CustomerSelectorViewModel
---
.../CustomerSection/CustomerSelectorViewModel.swift | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/WooCommerce/Classes/ViewRelated/Orders/Order Creation/CustomerSection/CustomerSelectorViewModel.swift b/WooCommerce/Classes/ViewRelated/Orders/Order Creation/CustomerSection/CustomerSelectorViewModel.swift
index 68ef00f5fca..3c65ed58453 100644
--- a/WooCommerce/Classes/ViewRelated/Orders/Order Creation/CustomerSection/CustomerSelectorViewModel.swift
+++ b/WooCommerce/Classes/ViewRelated/Orders/Order Creation/CustomerSection/CustomerSelectorViewModel.swift
@@ -44,15 +44,15 @@ final class CustomerSelectorViewModel {
/// Loads the whole customer information and calls the completion closures
///
func onCustomerSelected(_ customer: Customer, onCompletion: @escaping (Result<(), Error>) -> Void) {
- guard customer.customerID != 0 else {
+ guard customer.userID != 0 else {
// The customer is not registered, we won't get any further information. Dismiss and return data
onCustomerSelected(customer)
onCompletion(.success(()))
return
}
- // Get the full data about that customer
- stores.dispatch(CustomerAction.retrieveCustomer(siteID: siteID, customerID: customer.customerID, onCompletion: { [weak self] result in
+ // Get the full data about that customer using WordPress user ID
+ stores.dispatch(CustomerAction.retrieveCustomer(siteID: siteID, customerID: customer.userID, onCompletion: { [weak self] result in
switch result {
case .success(let customer):
self?.onCustomerSelected(customer)
From c2099df64d6bde0b810b8dcf60215cd351d1a5cb Mon Sep 17 00:00:00 2001
From: Povilas Staskus <4062343+staskus@users.noreply.github.com>
Date: Fri, 29 Aug 2025 00:03:25 +0300
Subject: [PATCH 09/12] Set userID when creating order
---
.../Orders/Order Creation/EditableOrderViewModel.swift | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/WooCommerce/Classes/ViewRelated/Orders/Order Creation/EditableOrderViewModel.swift b/WooCommerce/Classes/ViewRelated/Orders/Order Creation/EditableOrderViewModel.swift
index d94a43626e0..19c4e3a83b9 100644
--- a/WooCommerce/Classes/ViewRelated/Orders/Order Creation/EditableOrderViewModel.swift
+++ b/WooCommerce/Classes/ViewRelated/Orders/Order Creation/EditableOrderViewModel.swift
@@ -837,7 +837,9 @@ final class EditableOrderViewModel: ObservableObject {
let input = Self.createAddressesInputIfPossible(billingAddress: customer.billing, shippingAddress: customer.shipping)
// The customer ID needs to be set before the addresses, so that the customer ID doesn't get overridden by the API response (customer_id = 0
// by default) from updating the order's addresses remotely.
- orderSynchronizer.setCustomerID.send(customer.customerID)
+ // Use WordPress user ID (userID) for order creation, as the WooCommerce API expects customer_id to be the user ID who owns the order
+ // For guest customers (userID = 0), the API will handle this correctly
+ orderSynchronizer.setCustomerID.send(customer.userID)
orderSynchronizer.setAddresses.send(input)
resetAddressForm()
}
From 99eb9de636aabe6b9b72e442134a9eb40f3b7ba0 Mon Sep 17 00:00:00 2001
From: Povilas Staskus <4062343+staskus@users.noreply.github.com>
Date: Fri, 29 Aug 2025 00:03:38 +0300
Subject: [PATCH 10/12] Set userID in tests and previews
---
.../Classes/ViewRelated/Customers/CustomerDetailView.swift | 2 ++
.../Search/Customer/CustomerSearchUICommandTests.swift | 1 +
2 files changed, 3 insertions(+)
diff --git a/WooCommerce/Classes/ViewRelated/Customers/CustomerDetailView.swift b/WooCommerce/Classes/ViewRelated/Customers/CustomerDetailView.swift
index be4a9dbde90..fa354847bef 100644
--- a/WooCommerce/Classes/ViewRelated/Customers/CustomerDetailView.swift
+++ b/WooCommerce/Classes/ViewRelated/Customers/CustomerDetailView.swift
@@ -311,6 +311,7 @@ private extension CustomerDetailView {
#Preview("Customer") {
CustomerDetailView(viewModel: CustomerDetailViewModel(siteID: 1,
customerID: 0,
+ userID: 0,
name: "Pat Smith",
dateLastActive: "Jan 1, 2024",
email: "patsmith@example.com",
@@ -328,6 +329,7 @@ private extension CustomerDetailView {
#Preview("Customer with Placeholders") {
CustomerDetailView(viewModel: CustomerDetailViewModel(siteID: 1,
customerID: 0,
+ userID: 0,
name: "Guest",
dateLastActive: "Jan 1, 2024",
email: nil,
diff --git a/WooCommerce/WooCommerceTests/ViewRelated/Search/Customer/CustomerSearchUICommandTests.swift b/WooCommerce/WooCommerceTests/ViewRelated/Search/Customer/CustomerSearchUICommandTests.swift
index 24972cbab14..6af5598ec69 100644
--- a/WooCommerce/WooCommerceTests/ViewRelated/Search/Customer/CustomerSearchUICommandTests.swift
+++ b/WooCommerce/WooCommerceTests/ViewRelated/Search/Customer/CustomerSearchUICommandTests.swift
@@ -40,6 +40,7 @@ final class CustomerSearchUICommandTests: XCTestCase {
let command = CustomerSearchUICommand(siteID: sampleSiteID) { _ in }
let customer = Customer(
siteID: sampleSiteID,
+ userID: 0,
customerID: 1,
email: "john.w@email.com",
username: "john",
From b2c680ed2620f0af8f3f5b3082a1f7ff22014654 Mon Sep 17 00:00:00 2001
From: Povilas Staskus <4062343+staskus@users.noreply.github.com>
Date: Fri, 29 Aug 2025 00:03:48 +0300
Subject: [PATCH 11/12] Clarify code comment for customer retrieval
---
Modules/Sources/Networking/Remote/CustomerRemote.swift | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Modules/Sources/Networking/Remote/CustomerRemote.swift b/Modules/Sources/Networking/Remote/CustomerRemote.swift
index 275a5992a73..6a294e2b9a7 100644
--- a/Modules/Sources/Networking/Remote/CustomerRemote.swift
+++ b/Modules/Sources/Networking/Remote/CustomerRemote.swift
@@ -4,7 +4,7 @@ public class CustomerRemote: Remote {
/// Retrieves a `Customer`
///
/// - Parameters:
- /// - customerID: ID of the customer that will be retrieved
+ /// - customerID: ID of the registered WordPress user (customer) that will be retrieved.
/// - siteID: Site for which we'll fetch the customer.
/// - completion: Closure to be executed upon completion.
///
From 62ec3c572bea204def090bfc33eada9691cedc59 Mon Sep 17 00:00:00 2001
From: Povilas Staskus <4062343+staskus@users.noreply.github.com>
Date: Fri, 29 Aug 2025 11:11:34 +0300
Subject: [PATCH 12/12] Clarify customerID vs userID naming in CustomerStore
---
.../Networking/Remote/CustomerRemote.swift | 6 +--
.../Tools/StorageType+Extensions.swift | 18 ++++-----
.../Yosemite/Actions/CustomerAction.swift | 5 ++-
.../Customer+ReadOnlyConvertible.swift | 12 ++----
.../Yosemite/Stores/CustomerStore.swift | 38 ++++++++++---------
.../Mapper/CustomerMapperTests.swift | 6 ++-
.../Tools/StorageTypeExtensionsTests.swift | 35 -----------------
.../Stores/CustomerStoreTests.swift | 32 ++--------------
.../Customers/CustomerDetailViewModel.swift | 2 +-
.../CustomerSelectorViewModel.swift | 2 +-
.../CustomerSelectorViewModelTests.swift | 6 +--
11 files changed, 52 insertions(+), 110 deletions(-)
diff --git a/Modules/Sources/Networking/Remote/CustomerRemote.swift b/Modules/Sources/Networking/Remote/CustomerRemote.swift
index 6a294e2b9a7..8bed62612dc 100644
--- a/Modules/Sources/Networking/Remote/CustomerRemote.swift
+++ b/Modules/Sources/Networking/Remote/CustomerRemote.swift
@@ -4,12 +4,12 @@ public class CustomerRemote: Remote {
/// Retrieves a `Customer`
///
/// - Parameters:
- /// - customerID: ID of the registered WordPress user (customer) that will be retrieved.
+ /// - userID: ID of the registered WordPress user (customer) that will be retrieved.
/// - siteID: Site for which we'll fetch the customer.
/// - completion: Closure to be executed upon completion.
///
- public func retrieveCustomer(for siteID: Int64, with customerID: Int64, completion: @escaping (Result) -> Void) {
- let path = "customers/\(customerID)"
+ public func retrieveCustomer(for siteID: Int64, with userID: Int64, completion: @escaping (Result) -> Void) {
+ let path = "customers/\(userID)"
let request = JetpackRequest(wooApiVersion: .mark3,
method: .get,
siteID: siteID,
diff --git a/Modules/Sources/Storage/Tools/StorageType+Extensions.swift b/Modules/Sources/Storage/Tools/StorageType+Extensions.swift
index 0b3a9c92145..7480e106a4b 100644
--- a/Modules/Sources/Storage/Tools/StorageType+Extensions.swift
+++ b/Modules/Sources/Storage/Tools/StorageType+Extensions.swift
@@ -767,22 +767,22 @@ public extension StorageType {
// MARK: - Customers
- /// Returns a single Customer given a `siteID` and `customerID`
- ///
- func loadCustomer(siteID: Int64, customerID: Int64) -> Customer? {
- let predicate = \Customer.siteID == siteID && \Customer.customerID == customerID
- return firstObject(ofType: Customer.self, matching: predicate)
- }
-
func loadAllCustomers(siteID: Int64) -> [Customer] {
let predicate = \Customer.siteID == siteID
return allObjects(ofType: Customer.self, matching: predicate, sortedBy: [])
}
+ /// Returns stored Customers given a `siteID` matching `userIDs`
+ ///
+ func loadCustomers(siteID: Int64, matchingUserIDs userIDs: [Int64]) -> [Customer] {
+ let predicate = NSPredicate(format: "siteID == %lld && userID in %@", siteID, userIDs)
+ return allObjects(ofType: Customer.self, matching: predicate, sortedBy: [])
+ }
+
/// Returns stored Customers given a `siteID` matching `customerIDs`
///
- func loadCustomers(siteID: Int64, matching customerIDs: [Int64]) -> [Customer] {
- let predicate = NSPredicate(format: "siteID == %lld && customerID in %@", siteID, customerIDs)
+ func loadCustomers(siteID: Int64, matchingCustomerIDs userIDs: [Int64]) -> [Customer] {
+ let predicate = NSPredicate(format: "siteID == %lld && customerID in %@", siteID, userIDs)
return allObjects(ofType: Customer.self, matching: predicate, sortedBy: [])
}
diff --git a/Modules/Sources/Yosemite/Actions/CustomerAction.swift b/Modules/Sources/Yosemite/Actions/CustomerAction.swift
index 2d161fe10b9..55b390c1221 100644
--- a/Modules/Sources/Yosemite/Actions/CustomerAction.swift
+++ b/Modules/Sources/Yosemite/Actions/CustomerAction.swift
@@ -85,13 +85,14 @@ public enum CustomerAction: Action {
/// Retrieves a single Customer from a site
///
///- `siteID`: The site for which customers should be fetched.
- ///- `customerID`: ID of the Customer to be fetched.
+ ///- `customerID`: ID of the registered WordPress user (customer) that will be retrieved.
+
///- `onCompletion`: Invoked when the operation finishes.
/// - `result.success(Customer)`: The Customer object
/// - `result.failure(Error)`: Error fetching Customer
case retrieveCustomer(
siteID: Int64,
- customerID: Int64,
+ userID: Int64,
onCompletion: (Result) -> Void)
diff --git a/Modules/Sources/Yosemite/Model/Storage/Customer+ReadOnlyConvertible.swift b/Modules/Sources/Yosemite/Model/Storage/Customer+ReadOnlyConvertible.swift
index 018c57df06a..edc4d012750 100644
--- a/Modules/Sources/Yosemite/Model/Storage/Customer+ReadOnlyConvertible.swift
+++ b/Modules/Sources/Yosemite/Model/Storage/Customer+ReadOnlyConvertible.swift
@@ -7,16 +7,12 @@ import Storage
///
///
public protocol StorageCustomerConvertible {
- var loadingID: Int64 { get }
+ var userID: Int64 { get }
+ var customerID: Int64 { get }
}
-extension Yosemite.Customer: StorageCustomerConvertible {
- public var loadingID: Int64 { customerID }
-}
-
-extension Yosemite.WCAnalyticsCustomer: StorageCustomerConvertible {
- public var loadingID: Int64 { customerID }
-}
+extension Yosemite.Customer: StorageCustomerConvertible {}
+extension Yosemite.WCAnalyticsCustomer: StorageCustomerConvertible {}
// MARK: - Storage.Customer: ReadOnlyConvertible
//
diff --git a/Modules/Sources/Yosemite/Stores/CustomerStore.swift b/Modules/Sources/Yosemite/Stores/CustomerStore.swift
index 6225093c782..5f9e7911885 100644
--- a/Modules/Sources/Yosemite/Stores/CustomerStore.swift
+++ b/Modules/Sources/Yosemite/Stores/CustomerStore.swift
@@ -66,8 +66,8 @@ public final class CustomerStore: Store {
onCompletion: onCompletion)
case let .searchWCAnalyticsCustomers(siteID, pageNumber, pageSize, keyword, filter, onCompletion):
searchWCAnalyticsCustomers(for: siteID, pageNumber: pageNumber, pageSize: pageSize, keyword: keyword, filter: filter, onCompletion: onCompletion)
- case .retrieveCustomer(siteID: let siteID, customerID: let customerID, onCompletion: let onCompletion):
- retrieveCustomer(for: siteID, with: customerID, onCompletion: onCompletion)
+ case .retrieveCustomer(siteID: let siteID, userID: let userID, onCompletion: let onCompletion):
+ retrieveCustomer(for: siteID, with: userID, onCompletion: onCompletion)
case let .synchronizeLightCustomersData(siteID, pageNumber, pageSize, orderby, order, filterEmpty, onCompletion):
synchronizeLightCustomersData(siteID: siteID,
pageNumber: pageNumber,
@@ -174,14 +174,14 @@ public final class CustomerStore: Store {
///
/// - Parameters:
/// - siteID: The site for which customers should be fetched.
- /// - customerID: ID of the Customer to be fetched.
+ /// - customerID: ID of the registered WordPress user (customer) that will be retrieved.
/// - onCompletion: Invoked when the operation finishes. Will upsert the Customer to Storage, or return an Error.
///
func retrieveCustomer(
for siteID: Int64,
- with customerID: Int64,
+ with userID: Int64,
onCompletion: @escaping (Result) -> Void) {
- customerRemote.retrieveCustomer(for: siteID, with: customerID) { [weak self] result in
+ customerRemote.retrieveCustomer(for: siteID, with: userID) { [weak self] result in
guard let self else { return }
switch result {
case .success(let customer):
@@ -267,7 +267,7 @@ public final class CustomerStore: Store {
let group = DispatchGroup()
for result in searchResults {
// At the moment, we're not searching through non-registered customers
- // As we only search by customer ID, calls to /wc/v3/customers/0 will always fail
+ // As we only search by user ID, calls to /wc/v3/customers/0 will always fail
// https://github.com/woocommerce/woocommerce-ios/issues/7741
if result.userID == 0 {
continue
@@ -282,7 +282,7 @@ public final class CustomerStore: Store {
}
group.notify(queue: .main) {
- self.upsertSearchCustomerResult(
+ self.upsertRegisteredSearchCustomerResult(
siteID: siteID,
keyword: keyword,
readOnlyCustomers: customers,
@@ -297,11 +297,13 @@ public final class CustomerStore: Store {
// MARK: Storage operations
private extension CustomerStore {
/// Inserts or updates CustomerSearchResults in Storage
+ /// Only used in CommandSearchUICommand when .betterCustomerSelectionInOrder feature flag is disabled
+ /// Likely could be removed
///
- private func upsertSearchCustomerResult(siteID: Int64,
- keyword: String,
- readOnlyCustomers: [Networking.Customer],
- onCompletion: @escaping () -> Void) {
+ private func upsertRegisteredSearchCustomerResult(siteID: Int64,
+ keyword: String,
+ readOnlyCustomers: [Networking.Customer],
+ onCompletion: @escaping () -> Void) {
storageManager.performAndSave({ storage in
let storedSearchResult = storage.loadCustomerSearchResult(siteID: siteID, keyword: keyword) ??
storage.insertNewObject(ofType: Storage.CustomerSearchResult.self)
@@ -309,9 +311,9 @@ private extension CustomerStore {
storedSearchResult.siteID = siteID
storedSearchResult.keyword = keyword
- let storedCustomers = storage.loadCustomers(siteID: siteID, matching: readOnlyCustomers.map { $0.customerID })
+ let storedCustomers = storage.loadCustomers(siteID: siteID, matchingUserIDs: readOnlyCustomers.map { $0.userID })
for result in readOnlyCustomers {
- if let storedCustomer = storedCustomers.first(where: { $0.customerID == result.customerID }) {
+ if let storedCustomer = storedCustomers.first(where: { $0.userID == result.userID }) {
storedSearchResult.addToCustomers(storedCustomer)
}
}
@@ -328,7 +330,7 @@ private extension CustomerStore {
storage.deleteCustomers(siteID: siteID)
}
- let storedCustomers = storage.loadCustomers(siteID: siteID, matching: readOnlyCustomers.map { $0.loadingID })
+ let storedCustomers = storage.loadCustomers(siteID: siteID, matchingCustomerIDs: readOnlyCustomers.map { $0.customerID })
let storedSearchResult: CustomerSearchResult? = {
guard let keyword else {
return nil
@@ -395,11 +397,11 @@ private extension CustomerStore {
storedSearchResult: Storage.CustomerSearchResult?,
in storage: StorageType) {
let storageCustomer: Storage.Customer = {
- // If the specific customerID for that siteID already exists, return it
- // If doesn't or the user is unregistered (loadingID == 0), insert a new one in Storage
+ // If the specific userId for that siteID already exists, return it
+ // If doesn't or the user is unregistered (userId == 0), insert a new one in Storage
// Since we reset the customers everytime we request them, there's no risk of having duplicated unregistered customers
- if readOnlyCustomer.loadingID != 0,
- let storedCustomer = storedCustomers.first(where: { $0.customerID == readOnlyCustomer.loadingID }) {
+ if readOnlyCustomer.userID != 0,
+ let storedCustomer = storedCustomers.first(where: { $0.userID == readOnlyCustomer.userID }) {
return storedCustomer
} else {
return storage.insertNewObject(ofType: Storage.Customer.self)
diff --git a/Modules/Tests/NetworkingTests/Mapper/CustomerMapperTests.swift b/Modules/Tests/NetworkingTests/Mapper/CustomerMapperTests.swift
index 5845db59eee..49503d43263 100644
--- a/Modules/Tests/NetworkingTests/Mapper/CustomerMapperTests.swift
+++ b/Modules/Tests/NetworkingTests/Mapper/CustomerMapperTests.swift
@@ -44,7 +44,8 @@ class CustomerMapperTests: XCTestCase {
// Then
XCTAssertNotNil(customer)
- XCTAssertEqual(customer.customerID, 25)
+ XCTAssertEqual(customer.userID, 25)
+ XCTAssertEqual(customer.customerID, 0)
XCTAssertEqual(customer.email, "john.doe@example.com")
XCTAssertEqual(customer.firstName, "John")
XCTAssertEqual(customer.lastName, "Doe")
@@ -76,7 +77,8 @@ class CustomerMapperTests: XCTestCase {
// Then
XCTAssertNotNil(customer)
- XCTAssertEqual(customer.customerID, 25)
+ XCTAssertEqual(customer.userID, 25)
+ XCTAssertEqual(customer.customerID, 0)
XCTAssertEqual(customer.email, "john.doe@example.com")
XCTAssertEqual(customer.firstName, "John")
XCTAssertEqual(customer.lastName, "Doe")
diff --git a/Modules/Tests/StorageTests/Tools/StorageTypeExtensionsTests.swift b/Modules/Tests/StorageTests/Tools/StorageTypeExtensionsTests.swift
index 73986668f13..7b2a31667b3 100644
--- a/Modules/Tests/StorageTests/Tools/StorageTypeExtensionsTests.swift
+++ b/Modules/Tests/StorageTests/Tools/StorageTypeExtensionsTests.swift
@@ -175,41 +175,6 @@ final class StorageTypeExtensionsTests: XCTestCase {
XCTAssertEqual(coupon, storedCoupon)
}
- func test_loadCustomer_by_siteID_and_customerID() throws {
- // Given
- let customerID: Int64 = 123
- let customer = storage.insertNewObject(ofType: Customer.self)
- customer.siteID = sampleSiteID
- customer.customerID = customerID
-
- // When
- let storedCustomer = try XCTUnwrap(storage.loadCustomer(siteID: sampleSiteID, customerID: customerID))
-
- // Then
- XCTAssertEqual(customer, storedCustomer)
- }
-
- func test_loadCustomers_by_siteID_and_customerIDs() {
- // Given
- let customer1 = storage.insertNewObject(ofType: Customer.self)
- customer1.siteID = sampleSiteID
- customer1.customerID = 1
-
- let customer2 = storage.insertNewObject(ofType: Customer.self)
- customer2.siteID = sampleSiteID
- customer2.customerID = 2
-
- let customer3 = storage.insertNewObject(ofType: Customer.self)
- customer3.siteID = sampleSiteID
- customer3.customerID = 3
-
- // When
- let results = storage.loadCustomers(siteID: sampleSiteID, matching: [1, 3])
-
- // Then
- XCTAssertEqual(Set(results), Set([customer1, customer3]))
- }
-
func test_loadCustomerSearchResult_by_siteID_and_keyword() throws {
// Given
let keyword: String = "some keyword"
diff --git a/Modules/Tests/YosemiteTests/Stores/CustomerStoreTests.swift b/Modules/Tests/YosemiteTests/Stores/CustomerStoreTests.swift
index 47a302c6839..2ef48918b06 100644
--- a/Modules/Tests/YosemiteTests/Stores/CustomerStoreTests.swift
+++ b/Modules/Tests/YosemiteTests/Stores/CustomerStoreTests.swift
@@ -13,7 +13,7 @@ final class CustomerStoreTests: XCTestCase {
private var searchRemote: WCAnalyticsCustomerRemote!
private var store: CustomerStore!
private let dummySiteID: Int64 = 12345
- private let dummyCustomerID: Int64 = 25
+ private let dummyUserID: Int64 = 25
private let dummyKeyword: String = "John"
override func setUp() {
@@ -39,7 +39,7 @@ final class CustomerStoreTests: XCTestCase {
// When
let result: Result = waitFor { promise in
- let action = CustomerAction.retrieveCustomer(siteID: self.dummySiteID, customerID: self.dummyCustomerID) { result in
+ let action = CustomerAction.retrieveCustomer(siteID: self.dummySiteID, userID: self.dummyUserID) { result in
promise(result)
}
self.store.onAction(action)
@@ -48,7 +48,7 @@ final class CustomerStoreTests: XCTestCase {
// Then
XCTAssertTrue(result.isSuccess)
let customer = try result.get()
- XCTAssertEqual(customer.customerID, 25)
+ XCTAssertEqual(customer.userID, 25)
XCTAssertEqual(customer.firstName, "John")
XCTAssertEqual(customer.lastName, "Doe")
XCTAssertEqual(customer.email, "john.doe@example.com")
@@ -80,7 +80,7 @@ final class CustomerStoreTests: XCTestCase {
// When
let result: Result = waitFor { promise in
- let action = CustomerAction.retrieveCustomer(siteID: self.dummySiteID, customerID: self.dummyCustomerID) { result in
+ let action = CustomerAction.retrieveCustomer(siteID: self.dummySiteID, userID: self.dummyUserID) { result in
promise(result)
}
self.store.onAction(action)
@@ -200,30 +200,6 @@ final class CustomerStoreTests: XCTestCase {
XCTAssertTrue(storedCustomerSearchResults?.customers?.allSatisfy { $0.firstName?.contains(dummyKeyword) == true } ?? false )
}
- func test_retrieveCustomer_upserts_the_returned_Customer() {
- // Given
- network.simulateResponse(requestUrlSuffix: "customers/25", filename: "customer")
- XCTAssertEqual(viewStorage.countObjects(ofType: Storage.Customer.self), 0)
-
- // When
- let result: Result = waitFor { promise in
- let action = CustomerAction.retrieveCustomer(siteID: self.dummySiteID, customerID: self.dummyCustomerID) { result in
- promise(result)
- }
- self.store.onAction(action)
- }
-
- // Then
- XCTAssertTrue(result.isSuccess)
- XCTAssertEqual(viewStorage.countObjects(ofType: Storage.Customer.self), 1)
-
- let storedCustomer = viewStorage.loadCustomer(siteID: dummySiteID, customerID: dummyCustomerID)
- XCTAssertNotNil(storedCustomer)
- XCTAssertEqual(storedCustomer?.siteID, dummySiteID)
- XCTAssertEqual(storedCustomer?.customerID, dummyCustomerID)
- XCTAssertEqual(storedCustomer?.firstName, "John")
- }
-
func test_searchCustomers_returns_no_customers_when_customer_is_not_registered() throws {
// Given
network.simulateResponse(requestUrlSuffix: "customers", filename: "wc-analytics-customers")
diff --git a/WooCommerce/Classes/ViewRelated/Customers/CustomerDetailViewModel.swift b/WooCommerce/Classes/ViewRelated/Customers/CustomerDetailViewModel.swift
index f09c75e0ba4..210ee38b4d1 100644
--- a/WooCommerce/Classes/ViewRelated/Customers/CustomerDetailViewModel.swift
+++ b/WooCommerce/Classes/ViewRelated/Customers/CustomerDetailViewModel.swift
@@ -319,7 +319,7 @@ extension CustomerDetailViewModel {
// Don't show loading state if we already have customer billing or shipping data to display
updateStateIfNeeded(to: .loading)
- let action = CustomerAction.retrieveCustomer(siteID: siteID, customerID: userID) { [weak self] result in
+ let action = CustomerAction.retrieveCustomer(siteID: siteID, userID: userID) { [weak self] result in
guard let self else { return }
switch result {
case .success:
diff --git a/WooCommerce/Classes/ViewRelated/Orders/Order Creation/CustomerSection/CustomerSelectorViewModel.swift b/WooCommerce/Classes/ViewRelated/Orders/Order Creation/CustomerSection/CustomerSelectorViewModel.swift
index 3c65ed58453..bfb789bb55a 100644
--- a/WooCommerce/Classes/ViewRelated/Orders/Order Creation/CustomerSection/CustomerSelectorViewModel.swift
+++ b/WooCommerce/Classes/ViewRelated/Orders/Order Creation/CustomerSection/CustomerSelectorViewModel.swift
@@ -52,7 +52,7 @@ final class CustomerSelectorViewModel {
return
}
// Get the full data about that customer using WordPress user ID
- stores.dispatch(CustomerAction.retrieveCustomer(siteID: siteID, customerID: customer.userID, onCompletion: { [weak self] result in
+ stores.dispatch(CustomerAction.retrieveCustomer(siteID: siteID, userID: customer.userID, onCompletion: { [weak self] result in
switch result {
case .success(let customer):
self?.onCustomerSelected(customer)
diff --git a/WooCommerce/WooCommerceTests/ViewRelated/Orders/Order Creation/CustomerSection/CustomerSelectorViewModelTests.swift b/WooCommerce/WooCommerceTests/ViewRelated/Orders/Order Creation/CustomerSection/CustomerSelectorViewModelTests.swift
index 91b583a7fd6..dcc6beeb491 100644
--- a/WooCommerce/WooCommerceTests/ViewRelated/Orders/Order Creation/CustomerSection/CustomerSelectorViewModelTests.swift
+++ b/WooCommerce/WooCommerceTests/ViewRelated/Orders/Order Creation/CustomerSection/CustomerSelectorViewModelTests.swift
@@ -186,7 +186,7 @@ final class CustomerSelectorViewModelTests: XCTestCase {
passedCustomer = customer
}
- let returnedCustomer = Customer.fake().copy(customerID: 23, lastName: "Testion")
+ let returnedCustomer = Customer.fake().copy(userID: 23, customerID: 23, lastName: "Testion")
stores.whenReceivingAction(ofType: CustomerAction.self) { action in
switch action {
@@ -198,7 +198,7 @@ final class CustomerSelectorViewModelTests: XCTestCase {
}
// When
- let registeredCustomer = Customer.fake().copy(customerID: 23)
+ let registeredCustomer = Customer.fake().copy(userID: 23, customerID: 23)
var returnedResult: (Result<(), any Error>)?
waitForExpectation { expectation in
@@ -232,7 +232,7 @@ final class CustomerSelectorViewModelTests: XCTestCase {
}
// When
- let registeredCustomer = Customer.fake().copy(customerID: 23)
+ let registeredCustomer = Customer.fake().copy(userID: 23, customerID: 23)
var passedError: NSError?
waitForExpectation { expectation in
viewModel.onCustomerSelected(registeredCustomer) { result in