Skip to content

Commit 7ff28cc

Browse files
committed
Merge branch 'trunk' into woomob-1131-woo-poshistorical-orders-orders-fetching
2 parents 6f5e548 + 722d258 commit 7ff28cc

File tree

46 files changed

+2014
-169
lines changed

Some content is hidden

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

46 files changed

+2014
-169
lines changed

Modules/Sources/Experiments/DefaultFeatureFlagService.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public struct DefaultFeatureFlagService: FeatureFlagService {
9595
case .pointOfSaleOrdersi2:
9696
return true
9797
case .pointOfSaleSettingsi1:
98-
return false
98+
return buildConfig == .localDeveloper || buildConfig == .alpha
9999
case .orderAddressMapSearch:
100100
return true
101101
case .pointOfSaleHistoricalOrdersi1:

Modules/Sources/Fakes/Networking.generated.swift

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1776,7 +1776,8 @@ extension Networking.Site {
17761776
canBlaze: .fake(),
17771777
isAdmin: .fake(),
17781778
wasEcommerceTrial: .fake(),
1779-
hasSSOEnabled: .fake()
1779+
hasSSOEnabled: .fake(),
1780+
applicationPasswordAvailable: .fake()
17801781
)
17811782
}
17821783
}
@@ -2015,22 +2016,6 @@ extension Networking.UploadableMedia {
20152016
)
20162017
}
20172018
}
2018-
extension Networking.User {
2019-
/// Returns a "ready to use" type filled with fake values.
2020-
///
2021-
public static func fake() -> Networking.User {
2022-
.init(
2023-
localID: .fake(),
2024-
siteID: .fake(),
2025-
email: .fake(),
2026-
username: .fake(),
2027-
firstName: .fake(),
2028-
lastName: .fake(),
2029-
nickname: .fake(),
2030-
roles: .fake()
2031-
)
2032-
}
2033-
}
20342019
extension Networking.WCAnalyticsCustomer {
20352020
/// Returns a "ready to use" type filled with fake values.
20362021
///

Modules/Sources/Fakes/NetworkingCore.generated.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,3 +575,19 @@ extension NetworkingCore.StatsGranularityV4 {
575575
.hourly
576576
}
577577
}
578+
extension NetworkingCore.User {
579+
/// Returns a "ready to use" type filled with fake values.
580+
///
581+
public static func fake() -> NetworkingCore.User {
582+
.init(
583+
localID: .fake(),
584+
siteID: .fake(),
585+
email: .fake(),
586+
username: .fake(),
587+
firstName: .fake(),
588+
lastName: .fake(),
589+
nickname: .fake(),
590+
roles: .fake()
591+
)
592+
}
593+
}

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

Lines changed: 5 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2754,7 +2754,8 @@ extension Networking.Site {
27542754
canBlaze: CopiableProp<Bool> = .copy,
27552755
isAdmin: CopiableProp<Bool> = .copy,
27562756
wasEcommerceTrial: CopiableProp<Bool> = .copy,
2757-
hasSSOEnabled: CopiableProp<Bool> = .copy
2757+
hasSSOEnabled: CopiableProp<Bool> = .copy,
2758+
applicationPasswordAvailable: CopiableProp<Bool> = .copy
27582759
) -> Networking.Site {
27592760
let siteID = siteID ?? self.siteID
27602761
let name = name ?? self.name
@@ -2778,6 +2779,7 @@ extension Networking.Site {
27782779
let isAdmin = isAdmin ?? self.isAdmin
27792780
let wasEcommerceTrial = wasEcommerceTrial ?? self.wasEcommerceTrial
27802781
let hasSSOEnabled = hasSSOEnabled ?? self.hasSSOEnabled
2782+
let applicationPasswordAvailable = applicationPasswordAvailable ?? self.applicationPasswordAvailable
27812783

27822784
return Networking.Site(
27832785
siteID: siteID,
@@ -2801,7 +2803,8 @@ extension Networking.Site {
28012803
canBlaze: canBlaze,
28022804
isAdmin: isAdmin,
28032805
wasEcommerceTrial: wasEcommerceTrial,
2804-
hasSSOEnabled: hasSSOEnabled
2806+
hasSSOEnabled: hasSSOEnabled,
2807+
applicationPasswordAvailable: applicationPasswordAvailable
28052808
)
28062809
}
28072810
}
@@ -3097,39 +3100,6 @@ extension Networking.TopEarnerStatsItem {
30973100
}
30983101
}
30993102

3100-
extension Networking.User {
3101-
public func copy(
3102-
localID: CopiableProp<Int64> = .copy,
3103-
siteID: CopiableProp<Int64> = .copy,
3104-
email: CopiableProp<String> = .copy,
3105-
username: CopiableProp<String> = .copy,
3106-
firstName: CopiableProp<String> = .copy,
3107-
lastName: CopiableProp<String> = .copy,
3108-
nickname: CopiableProp<String> = .copy,
3109-
roles: CopiableProp<[String]> = .copy
3110-
) -> Networking.User {
3111-
let localID = localID ?? self.localID
3112-
let siteID = siteID ?? self.siteID
3113-
let email = email ?? self.email
3114-
let username = username ?? self.username
3115-
let firstName = firstName ?? self.firstName
3116-
let lastName = lastName ?? self.lastName
3117-
let nickname = nickname ?? self.nickname
3118-
let roles = roles ?? self.roles
3119-
3120-
return Networking.User(
3121-
localID: localID,
3122-
siteID: siteID,
3123-
email: email,
3124-
username: username,
3125-
firstName: firstName,
3126-
lastName: lastName,
3127-
nickname: nickname,
3128-
roles: roles
3129-
)
3130-
}
3131-
}
3132-
31333103
extension Networking.WCAnalyticsCustomer {
31343104
public func copy(
31353105
siteID: CopiableProp<Int64> = .copy,

Modules/Sources/Networking/Model/Site.swift

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ public struct Site: Decodable, Equatable, Hashable, GeneratedFakeable, Generated
9292
///
9393
public let hasSSOEnabled: Bool
9494

95+
/// Whether application password authentication is available
96+
/// periphery: ignore - to be used as part of WOOMOB-1123
97+
public let applicationPasswordAvailable: Bool
98+
9599
/// Decodable Conformance.
96100
///
97101
public init(from decoder: Decoder) throws {
@@ -156,7 +160,8 @@ public struct Site: Decodable, Equatable, Hashable, GeneratedFakeable, Generated
156160
canBlaze: canBlaze,
157161
isAdmin: isAdmin,
158162
wasEcommerceTrial: wasEcommerceTrial,
159-
hasSSOEnabled: hasSSOEnabled)
163+
hasSSOEnabled: hasSSOEnabled,
164+
applicationPasswordAvailable: false) // to be updated by fetching SiteAPI
160165
}
161166

162167
/// Designated Initializer.
@@ -182,7 +187,8 @@ public struct Site: Decodable, Equatable, Hashable, GeneratedFakeable, Generated
182187
canBlaze: Bool,
183188
isAdmin: Bool,
184189
wasEcommerceTrial: Bool,
185-
hasSSOEnabled: Bool) {
190+
hasSSOEnabled: Bool,
191+
applicationPasswordAvailable: Bool) {
186192
self.siteID = siteID
187193
self.name = name
188194
self.description = description
@@ -205,6 +211,7 @@ public struct Site: Decodable, Equatable, Hashable, GeneratedFakeable, Generated
205211
self.isAdmin = isAdmin
206212
self.wasEcommerceTrial = wasEcommerceTrial
207213
self.hasSSOEnabled = hasSSOEnabled
214+
self.applicationPasswordAvailable = applicationPasswordAvailable
208215
}
209216
}
210217

Modules/Sources/Networking/Model/WordPressSite.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@ public extension WordPressSite {
109109
canBlaze: false,
110110
isAdmin: false,
111111
wasEcommerceTrial: false,
112-
hasSSOEnabled: false)
112+
hasSSOEnabled: false,
113+
applicationPasswordAvailable: false)
113114
}
114115

115116
struct Authentication: Decodable {

Modules/Sources/Networking/Remote/POSCatalogSyncRemote.swift

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,64 @@ public class POSCatalogSyncRemote: Remote {
5555

5656
return createPagedItems(items: variations, responseHeaders: responseHeaders, currentPageNumber: pageNumber)
5757
}
58+
59+
/// Generates a POS catalog. The catalog is generated asynchronously and a download URL is returned in the
60+
/// status response endpoint associated with a job ID.
61+
///
62+
/// - Parameters:
63+
/// - siteID: Site ID to generate catalog for.
64+
/// - fields: Optional array of fields to include in catalog.
65+
/// - forceGenerate: Whether to force generation of a new catalog.
66+
/// - Returns: Catalog job response with job ID.
67+
///
68+
// periphery:ignore - TODO - remove this periphery ignore comment when this endpoint is integrated with catalog sync
69+
public func generateCatalog(for siteID: Int64, forceGenerate: Bool = false) async throws -> POSCatalogGenerationResponse {
70+
let path = "catalog"
71+
let parameters: [String: Any] = [
72+
ParameterKey.fullSyncFields: POSProduct.requestFields
73+
]
74+
75+
let request = JetpackRequest(wooApiVersion: .mark3, method: .post, siteID: siteID, path: path, parameters: parameters, availableAsRESTRequest: true)
76+
let mapper = SingleItemMapper<POSCatalogGenerationResponse>(siteID: siteID)
77+
return try await enqueue(request, mapper: mapper)
78+
}
79+
80+
/// Checks the status of a catalog generation job. A download URL is returned when the job is complete.
81+
///
82+
/// - Parameters:
83+
/// - siteID: Site ID for the catalog job.
84+
/// - jobID: Job ID to check status for.
85+
/// - Returns: Catalog status response.
86+
///
87+
// periphery:ignore - TODO - remove this periphery ignore comment when this endpoint is integrated with catalog sync
88+
public func checkCatalogStatus(for siteID: Int64, jobID: String) async throws -> POSCatalogStatusResponse {
89+
let path = "catalog/status/\(jobID)"
90+
91+
let request = JetpackRequest(wooApiVersion: .mark3, method: .get, siteID: siteID, path: path, availableAsRESTRequest: true)
92+
let mapper = SingleItemMapper<POSCatalogStatusResponse>(siteID: siteID)
93+
return try await enqueue(request, mapper: mapper)
94+
}
95+
96+
/// Downloads the generated catalog at the specified download URL.
97+
/// - Parameters:
98+
/// - siteID: Site ID to download catalog for.
99+
/// - downloadURL: Download URL of the catalog file.
100+
/// - Returns: List of products and variations in the POS catalog.
101+
// periphery:ignore - TODO - remove this periphery ignore comment when this method is integrated with catalog sync
102+
public func downloadCatalog(for siteID: Int64, downloadURL: String) async throws -> POSCatalog {
103+
// TODO: WOOMOB-1173 - move download task to the background using `URLSessionConfiguration.background`
104+
guard let url = URL(string: downloadURL) else {
105+
throw NetworkError.invalidURL
106+
}
107+
let request = URLRequest(url: url)
108+
let mapper = ListMapper<POSProduct>(siteID: siteID)
109+
let items = try await enqueue(request, mapper: mapper)
110+
let variationProductTypeKey = "variation"
111+
let products = items.filter { $0.productTypeKey != variationProductTypeKey }
112+
let variations = items.filter { $0.productTypeKey == variationProductTypeKey }
113+
.map { $0.toVariation }
114+
return POSCatalog(products: products, variations: variations)
115+
}
58116
}
59117

60118
// MARK: - Constants
@@ -69,5 +127,78 @@ private extension POSCatalogSyncRemote {
69127
static let page = "page"
70128
static let perPage = "per_page"
71129
static let fields = "_fields"
130+
static let fullSyncFields = "fields"
131+
}
132+
}
133+
134+
// MARK: - Response Models
135+
136+
/// Response from catalog generation request.
137+
// periphery:ignore - TODO - remove this periphery ignore comment when the corresponding endpoint is integrated with catalog sync
138+
public struct POSCatalogGenerationResponse: Decodable {
139+
/// Unique identifier for tracking the catalog generation job.
140+
public let jobID: String
141+
142+
private enum CodingKeys: String, CodingKey {
143+
case jobID = "job_id"
144+
}
145+
}
146+
147+
/// Response from catalog status check.
148+
// periphery:ignore - TODO - remove this periphery ignore comment when the corresponding endpoint is integrated with catalog sync
149+
public struct POSCatalogStatusResponse: Decodable {
150+
/// Current status of the catalog generation job.
151+
public let status: POSCatalogStatus
152+
/// Download URL for the completed catalog (available when status is complete).
153+
public let downloadURL: String?
154+
/// Progress percentage of the catalog generation (0.0 to 100.0).
155+
public let progress: Double
156+
157+
private enum CodingKeys: String, CodingKey {
158+
case status
159+
case downloadURL = "download_url"
160+
case progress
161+
}
162+
}
163+
164+
/// Catalog generation status.
165+
public enum POSCatalogStatus: String, Decodable {
166+
case pending
167+
case processing
168+
case complete
169+
}
170+
171+
/// POS catalog from download.
172+
// periphery:ignore - TODO - remove this periphery ignore comment when the corresponding endpoint is integrated with catalog sync
173+
public struct POSCatalog {
174+
public let products: [POSProduct]
175+
public let variations: [POSProductVariation]
176+
}
177+
178+
private extension POSProduct {
179+
var toVariation: POSProductVariation {
180+
let variationAttributes = attributes.compactMap { attribute in
181+
try? attribute.toProductVariationAttribute()
182+
}
183+
184+
let firstImage = images.first
185+
186+
return .init(
187+
siteID: siteID,
188+
productID: parentID,
189+
productVariationID: productID,
190+
attributes: variationAttributes,
191+
image: firstImage,
192+
sku: sku,
193+
globalUniqueID: globalUniqueID,
194+
price: price,
195+
regularPrice: regularPrice,
196+
salePrice: salePrice,
197+
onSale: onSale,
198+
downloadable: downloadable,
199+
manageStock: manageStock,
200+
stockQuantity: stockQuantity,
201+
stockStatusKey: stockStatusKey
202+
)
72203
}
73204
}

0 commit comments

Comments
 (0)