Skip to content

Commit 7198db0

Browse files
authored
Merge branch 'trunk' into woomob-1231-ios-bookings-tab
2 parents 35c4988 + 5a7ceb2 commit 7198db0

File tree

87 files changed

+5564
-358
lines changed

Some content is hidden

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

87 files changed

+5564
-358
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
<!--
22
Contains editorialized release notes. Raw release notes should go into `RELEASE-NOTES.txt`.
33
-->
4+
## 23.3
5+
Enjoy a smoother store management experience with clearer shipping labels for physical items, friendlier product code error messages, more reliable custom fields, and better app performance for users authenticated with WordPress.com. All designed to streamline your daily workflow.
6+
47
## 23.2
58
This update smooths your WooCommerce experience with improved cash payments, easier access to POS settings, and accurate HAZMAT details on shipping labels. Plus, we fixed a Blaze flow issue so campaigns behave as expected. Faster, clearer, and more reliable — just how you need it!
69

Modules/Sources/Fakes/Networking.generated.swift

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,31 @@ extension Networking.BlazeTargetTopic {
317317
)
318318
}
319319
}
320+
extension Networking.Booking {
321+
/// Returns a "ready to use" type filled with fake values.
322+
///
323+
public static func fake() -> Networking.Booking {
324+
.init(
325+
siteID: .fake(),
326+
bookingID: .fake(),
327+
allDay: .fake(),
328+
cost: .fake(),
329+
customerID: .fake(),
330+
dateCreated: .fake(),
331+
dateModified: .fake(),
332+
endDate: .fake(),
333+
googleCalendarEventID: .fake(),
334+
orderID: .fake(),
335+
orderItemID: .fake(),
336+
parentID: .fake(),
337+
productID: .fake(),
338+
resourceID: .fake(),
339+
startDate: .fake(),
340+
statusKey: .fake(),
341+
localTimezone: .fake()
342+
)
343+
}
344+
}
320345
extension Networking.CompositeComponentOptionType {
321346
/// Returns a "ready to use" type filled with fake values.
322347
///
@@ -1775,9 +1800,9 @@ extension Networking.Site {
17751800
wasEcommerceTrial: .fake(),
17761801
hasSSOEnabled: .fake(),
17771802
applicationPasswordAvailable: .fake(),
1778-
isGarden: false,
1779-
gardenName: nil,
1780-
gardenPartner: nil
1803+
isGarden: .fake(),
1804+
gardenName: .fake(),
1805+
gardenPartner: .fake()
17811806
)
17821807
}
17831808
}
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
import Codegen
2+
import Foundation
3+
4+
/// Represents a Booking Entity.
5+
///
6+
public struct Booking: Codable, GeneratedCopiable, Equatable, GeneratedFakeable {
7+
public let siteID: Int64
8+
public let bookingID: Int64
9+
public let allDay: Bool
10+
public let cost: String
11+
public let customerID: Int64
12+
public let dateCreated: Date
13+
public let dateModified: Date
14+
public let endDate: Date
15+
public let googleCalendarEventID: String?
16+
public let orderID: Int64
17+
public let orderItemID: Int64
18+
public let parentID: Int64
19+
public let productID: Int64
20+
public let resourceID: Int64
21+
public let startDate: Date
22+
public let statusKey: String
23+
public let localTimezone: String
24+
25+
// periphery: ignore - to be used later
26+
public var bookingStatus: BookingStatus {
27+
return BookingStatus(rawValue: statusKey) ?? .unknown
28+
}
29+
30+
/// Booking struct initializer.
31+
///
32+
public init(siteID: Int64,
33+
bookingID: Int64,
34+
allDay: Bool,
35+
cost: String,
36+
customerID: Int64,
37+
dateCreated: Date,
38+
dateModified: Date,
39+
endDate: Date,
40+
googleCalendarEventID: String?,
41+
orderID: Int64,
42+
orderItemID: Int64,
43+
parentID: Int64,
44+
productID: Int64,
45+
resourceID: Int64,
46+
startDate: Date,
47+
statusKey: String,
48+
localTimezone: String) {
49+
self.siteID = siteID
50+
self.bookingID = bookingID
51+
self.allDay = allDay
52+
self.cost = cost
53+
self.customerID = customerID
54+
self.dateCreated = dateCreated
55+
self.dateModified = dateModified
56+
self.endDate = endDate
57+
self.googleCalendarEventID = googleCalendarEventID
58+
self.orderID = orderID
59+
self.orderItemID = orderItemID
60+
self.parentID = parentID
61+
self.productID = productID
62+
self.resourceID = resourceID
63+
self.startDate = startDate
64+
self.statusKey = statusKey
65+
self.localTimezone = localTimezone
66+
}
67+
68+
/// The public initializer for Booking.
69+
///
70+
public init(from decoder: Decoder) throws {
71+
guard let siteID = decoder.userInfo[.siteID] as? Int64 else {
72+
throw BookingDecodingError.missingSiteID
73+
}
74+
75+
let container = try decoder.container(keyedBy: CodingKeys.self)
76+
77+
let bookingID = try container.decode(Int64.self, forKey: .bookingID)
78+
let allDay = try container.decode(Bool.self, forKey: .allDay)
79+
80+
// Cost may come as string or number
81+
let cost = container.failsafeDecodeIfPresent(targetType: String.self,
82+
forKey: .cost,
83+
alternativeTypes: [.decimal(transform: { NSDecimalNumber(decimal: $0).stringValue })]) ?? ""
84+
85+
let customerID = try container.decode(Int64.self, forKey: .customerID)
86+
let dateCreated = Date(timeIntervalSince1970: try container.decode(Double.self, forKey: .dateCreated))
87+
let dateModified = Date(timeIntervalSince1970: try container.decode(Double.self, forKey: .dateModified))
88+
let endDate = Date(timeIntervalSince1970: try container.decode(Double.self, forKey: .endDate))
89+
let googleCalendarEventID = try container.decodeIfPresent(String.self, forKey: .googleCalendarEventID)
90+
let orderID = try container.decode(Int64.self, forKey: .orderID)
91+
let orderItemID = try container.decode(Int64.self, forKey: .orderItemID)
92+
let parentID = try container.decode(Int64.self, forKey: .parentID)
93+
let productID = try container.decode(Int64.self, forKey: .productID)
94+
let resourceID = try container.decode(Int64.self, forKey: .resourceID)
95+
let startDate = Date(timeIntervalSince1970: try container.decode(Double.self, forKey: .startDate))
96+
let statusKey = try container.decode(String.self, forKey: .statusKey)
97+
let localTimezone = try container.decode(String.self, forKey: .localTimezone)
98+
99+
self.init(siteID: siteID,
100+
bookingID: bookingID,
101+
allDay: allDay,
102+
cost: cost,
103+
customerID: customerID,
104+
dateCreated: dateCreated,
105+
dateModified: dateModified,
106+
endDate: endDate,
107+
googleCalendarEventID: googleCalendarEventID,
108+
orderID: orderID,
109+
orderItemID: orderItemID,
110+
parentID: parentID,
111+
productID: productID,
112+
resourceID: resourceID,
113+
startDate: startDate,
114+
statusKey: statusKey,
115+
localTimezone: localTimezone)
116+
}
117+
118+
public func encode(to encoder: Encoder) throws {
119+
var container = encoder.container(keyedBy: CodingKeys.self)
120+
121+
try container.encode(bookingID, forKey: .bookingID)
122+
try container.encode(allDay, forKey: .allDay)
123+
try container.encode(cost, forKey: .cost)
124+
try container.encode(customerID, forKey: .customerID)
125+
try container.encode(dateCreated, forKey: .dateCreated)
126+
try container.encode(dateModified, forKey: .dateModified)
127+
try container.encode(endDate, forKey: .endDate)
128+
try container.encode(googleCalendarEventID, forKey: .googleCalendarEventID)
129+
try container.encode(orderID, forKey: .orderID)
130+
try container.encode(orderItemID, forKey: .orderItemID)
131+
try container.encode(parentID, forKey: .parentID)
132+
try container.encode(productID, forKey: .productID)
133+
try container.encode(resourceID, forKey: .resourceID)
134+
try container.encode(startDate, forKey: .startDate)
135+
try container.encode(statusKey, forKey: .statusKey)
136+
try container.encode(localTimezone, forKey: .localTimezone)
137+
}
138+
}
139+
140+
/// Defines all of the Booking CodingKeys
141+
///
142+
private extension Booking {
143+
144+
enum CodingKeys: String, CodingKey {
145+
case bookingID = "id"
146+
case allDay = "all_day"
147+
case cost
148+
case customerID = "customer_id"
149+
case dateCreated = "date_created"
150+
case dateModified = "date_modified"
151+
case endDate = "end"
152+
case googleCalendarEventID = "google_calendar_event_id"
153+
case orderID = "order_id"
154+
case orderItemID = "order_item_id"
155+
case parentID = "parent_id"
156+
case personCounts = "person_counts"
157+
case productID = "product_id"
158+
case resourceID = "resource_id"
159+
case startDate = "start"
160+
case statusKey = "status"
161+
case localTimezone = "local_timezone"
162+
}
163+
}
164+
165+
// MARK: - Decoding Errors
166+
//
167+
enum BookingDecodingError: Error {
168+
case missingSiteID
169+
}
170+
171+
// MARK: - Supporting Types
172+
//
173+
174+
// periphery: ignore
175+
/// Represents a Booking Status.
176+
public enum BookingStatus: String, CaseIterable {
177+
case complete
178+
case paid
179+
case unpaid
180+
case cancelled
181+
case pendingConfirmation = "pending-confirmation"
182+
case confirmed
183+
case inCart = "in-cart"
184+
case unknown
185+
}

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

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,66 @@ extension Networking.BlazeTargetTopic {
428428
}
429429
}
430430

431+
extension Networking.Booking {
432+
public func copy(
433+
siteID: CopiableProp<Int64> = .copy,
434+
bookingID: CopiableProp<Int64> = .copy,
435+
allDay: CopiableProp<Bool> = .copy,
436+
cost: CopiableProp<String> = .copy,
437+
customerID: CopiableProp<Int64> = .copy,
438+
dateCreated: CopiableProp<Date> = .copy,
439+
dateModified: CopiableProp<Date> = .copy,
440+
endDate: CopiableProp<Date> = .copy,
441+
googleCalendarEventID: NullableCopiableProp<String> = .copy,
442+
orderID: CopiableProp<Int64> = .copy,
443+
orderItemID: CopiableProp<Int64> = .copy,
444+
parentID: CopiableProp<Int64> = .copy,
445+
productID: CopiableProp<Int64> = .copy,
446+
resourceID: CopiableProp<Int64> = .copy,
447+
startDate: CopiableProp<Date> = .copy,
448+
statusKey: CopiableProp<String> = .copy,
449+
localTimezone: CopiableProp<String> = .copy
450+
) -> Networking.Booking {
451+
let siteID = siteID ?? self.siteID
452+
let bookingID = bookingID ?? self.bookingID
453+
let allDay = allDay ?? self.allDay
454+
let cost = cost ?? self.cost
455+
let customerID = customerID ?? self.customerID
456+
let dateCreated = dateCreated ?? self.dateCreated
457+
let dateModified = dateModified ?? self.dateModified
458+
let endDate = endDate ?? self.endDate
459+
let googleCalendarEventID = googleCalendarEventID ?? self.googleCalendarEventID
460+
let orderID = orderID ?? self.orderID
461+
let orderItemID = orderItemID ?? self.orderItemID
462+
let parentID = parentID ?? self.parentID
463+
let productID = productID ?? self.productID
464+
let resourceID = resourceID ?? self.resourceID
465+
let startDate = startDate ?? self.startDate
466+
let statusKey = statusKey ?? self.statusKey
467+
let localTimezone = localTimezone ?? self.localTimezone
468+
469+
return Networking.Booking(
470+
siteID: siteID,
471+
bookingID: bookingID,
472+
allDay: allDay,
473+
cost: cost,
474+
customerID: customerID,
475+
dateCreated: dateCreated,
476+
dateModified: dateModified,
477+
endDate: endDate,
478+
googleCalendarEventID: googleCalendarEventID,
479+
orderID: orderID,
480+
orderItemID: orderItemID,
481+
parentID: parentID,
482+
productID: productID,
483+
resourceID: resourceID,
484+
startDate: startDate,
485+
statusKey: statusKey,
486+
localTimezone: localTimezone
487+
)
488+
}
489+
}
490+
431491
extension Networking.Coupon {
432492
public func copy(
433493
siteID: CopiableProp<Int64> = .copy,
@@ -2749,8 +2809,8 @@ extension Networking.Site {
27492809
hasSSOEnabled: CopiableProp<Bool> = .copy,
27502810
applicationPasswordAvailable: CopiableProp<Bool> = .copy,
27512811
isGarden: CopiableProp<Bool> = .copy,
2752-
gardenName: CopiableProp<String?> = .copy,
2753-
gardenPartner: CopiableProp<String?> = .copy
2812+
gardenName: NullableCopiableProp<String> = .copy,
2813+
gardenPartner: NullableCopiableProp<String> = .copy
27542814
) -> Networking.Site {
27552815
let siteID = siteID ?? self.siteID
27562816
let name = name ?? self.name
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// periphery:ignore:all
2+
import Foundation
3+
4+
/// Protocol for `BookingsRemote` mainly used for mocking.
5+
///
6+
/// The required methods are intentionally incomplete. Feel free to add the other ones.
7+
///
8+
public protocol BookingsRemoteProtocol {
9+
func loadAllBookings(for siteID: Int64,
10+
pageNumber: Int,
11+
pageSize: Int) async throws -> [Booking]
12+
}
13+
14+
/// Booking: Remote Endpoints
15+
///
16+
public final class BookingsRemote: Remote, BookingsRemoteProtocol {
17+
18+
// MARK: - Bookings
19+
20+
/// Retrieves all of the `Bookings` available.
21+
///
22+
/// - Parameters:
23+
/// - siteID: Site for which we'll fetch remote bookings.
24+
/// - pageNumber: Number of page that should be retrieved.
25+
/// - pageSize: Number of bookings to be retrieved per page.
26+
///
27+
public func loadAllBookings(for siteID: Int64,
28+
pageNumber: Int = Default.pageNumber,
29+
pageSize: Int = Default.pageSize) async throws -> [Booking] {
30+
let parameters = [
31+
ParameterKey.page: String(pageNumber),
32+
ParameterKey.perPage: String(pageSize)
33+
]
34+
35+
let path = Path.bookings
36+
let request = JetpackRequest(wooApiVersion: .wcBookings, method: .get, siteID: siteID, path: path, parameters: parameters, availableAsRESTRequest: true)
37+
let mapper = ListMapper<Booking>(siteID: siteID)
38+
39+
return try await enqueue(request, mapper: mapper)
40+
}
41+
}
42+
43+
// MARK: - Constants
44+
//
45+
public extension BookingsRemote {
46+
enum Default {
47+
public static let pageSize: Int = 25
48+
public static let pageNumber: Int = Remote.Default.firstPageNumber
49+
}
50+
51+
private enum Path {
52+
static let bookings = "bookings"
53+
}
54+
55+
private enum ParameterKey {
56+
static let page: String = "page"
57+
static let perPage: String = "per_page"
58+
}
59+
}

Modules/Sources/NetworkingCore/Settings/WooAPIVersion.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ public enum WooAPIVersion: String {
5050
///
5151
case wooShipping = "wcshipping/v1"
5252

53+
/// WooCommerce Bookings Plugin V1.
54+
///
55+
case wcBookings = "wc-bookings/v2"
56+
5357
/// Returns the path for the current API Version
5458
///
5559
var path: String {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import Foundation
2+
import CoreData
3+
4+
@objc(Booking)
5+
public class Booking: NSManagedObject {
6+
7+
}

0 commit comments

Comments
 (0)