Skip to content

Commit 49535da

Browse files
committed
Merge branch 'trunk' into WOOMOB-1553-hide-card-reader-for-CIAB-sites
# Conflicts: # Modules/Sources/Yosemite/Tools/CIAB/CIABEligibilityCheckerProtocol.swift # WooCommerce/Classes/ViewRelated/Dashboard/Settings/POS/POSTabVisibilityChecker.swift
2 parents 98965ff + 06e16dd commit 49535da

File tree

45 files changed

+1332
-162
lines changed

Some content is hidden

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

45 files changed

+1332
-162
lines changed

Modules/Sources/Networking/Model/Bookings/Booking.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ public struct Booking: Codable, GeneratedCopiable, Hashable, GeneratedFakeable {
2929
return BookingStatus(rawValue: statusKey) ?? .unknown
3030
}
3131

32-
/// periphery: ignore - will be used in UI in upcoming PRs
3332
public var attendanceStatus: BookingAttendanceStatus {
3433
return BookingAttendanceStatus(rawValue: attendanceStatusKey) ?? .unknown
3534
}
@@ -208,7 +207,6 @@ public enum BookingStatus: String, CaseIterable {
208207
case unknown
209208
}
210209

211-
/// periphery: ignore - will be used in UI in upcoming PRs
212210
public enum BookingAttendanceStatus: String, CaseIterable {
213211
case booked
214212
case checkedIn = "checked-in"

Modules/Sources/Networking/Remote/BookingsRemote.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ public protocol BookingsRemoteProtocol {
1717
func loadBooking(bookingID: Int64,
1818
siteID: Int64) async throws -> Booking?
1919

20+
func updateBooking(
21+
from siteID: Int64,
22+
bookingID: Int64,
23+
attendanceStatus: BookingAttendanceStatus
24+
) async throws -> Booking?
25+
2026
func fetchResource(resourceID: Int64,
2127
siteID: Int64) async throws -> BookingResource?
2228
}
@@ -88,6 +94,28 @@ public final class BookingsRemote: Remote, BookingsRemoteProtocol {
8894
return try await enqueue(request, mapper: mapper)
8995
}
9096

97+
public func updateBooking(
98+
from siteID: Int64,
99+
bookingID: Int64,
100+
attendanceStatus: BookingAttendanceStatus
101+
) async throws -> Booking? {
102+
let path = "\(Path.bookings)/\(bookingID)"
103+
let parameters = [
104+
ParameterKey.attendanceStatus: attendanceStatus.rawValue
105+
]
106+
let request = JetpackRequest(
107+
wooApiVersion: .wcBookings,
108+
method: .put,
109+
siteID: siteID,
110+
path: path,
111+
parameters: parameters,
112+
availableAsRESTRequest: true
113+
)
114+
115+
let mapper = BookingMapper(siteID: siteID)
116+
return try await enqueue(request, mapper: mapper)
117+
}
118+
91119
public func fetchResource(
92120
resourceID: Int64,
93121
siteID: Int64
@@ -132,5 +160,6 @@ public extension BookingsRemote {
132160
static let startDateAfter: String = "start_date_after"
133161
static let search: String = "search"
134162
static let order: String = "order"
163+
static let attendanceStatus = "attendance_status"
135164
}
136165
}

Modules/Sources/Yosemite/Actions/BookingAction.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,16 @@ public enum BookingAction: Action {
5252
case fetchResource(siteID: Int64,
5353
resourceID: Int64,
5454
onCompletion: (Result<BookingResource, Error>) -> Void)
55+
56+
/// Updates a booking attendance status.
57+
///
58+
/// - Parameter siteID: The site ID of the booking.
59+
/// - Parameter bookingID: The ID of the booking to be updated.
60+
/// - Parameter status: The new attendance status.
61+
/// - Parameter onCompletion: called when update completes, returns an error in case of a failure.
62+
///
63+
case updateBookingAttendanceStatus(siteID: Int64,
64+
bookingID: Int64,
65+
status: BookingAttendanceStatus,
66+
onCompletion: (Error?) -> Void)
5567
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// periphery:ignore:all - will be used for booking filters
2+
import Foundation
3+
4+
/// Used to filter bookings by date range
5+
///
6+
public struct BookingDateRangeFilter: Codable, Equatable, Hashable {
7+
/// Start date of the range (inclusive)
8+
///
9+
public let startDate: Date?
10+
11+
/// End date of the range (inclusive)
12+
///
13+
public let endDate: Date?
14+
15+
public init(startDate: Date? = nil,
16+
endDate: Date? = nil) {
17+
self.startDate = startDate
18+
self.endDate = endDate
19+
}
20+
21+
enum CodingKeys: String, CodingKey {
22+
case startDate = "start_date"
23+
case endDate = "end_date"
24+
}
25+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// periphery:ignore:all - will be used for booking filters
2+
import Foundation
3+
4+
/// Used to filter bookings by product
5+
///
6+
public struct BookingProductFilter: Codable, Hashable {
7+
/// ID of the product
8+
///
9+
public let id: Int64
10+
11+
/// Name of the product
12+
///
13+
public let name: String
14+
15+
public init(id: Int64,
16+
name: String) {
17+
self.id = id
18+
self.name = name
19+
}
20+
}

Modules/Sources/Yosemite/Model/Model.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@ public typealias BlazeTargetOptions = Networking.BlazeTargetOptions
2626
public typealias BlazeTargetLocation = Networking.BlazeTargetLocation
2727
public typealias BlazeTargetTopic = Networking.BlazeTargetTopic
2828
public typealias Booking = Networking.Booking
29+
public typealias BookingStatus = Networking.BookingStatus
2930
public typealias BookingOrderInfo = Networking.BookingOrderInfo
3031
public typealias BookingCustomerInfo = Networking.BookingCustomerInfo
3132
public typealias BookingPaymentInfo = Networking.BookingPaymentInfo
3233
public typealias BookingProductInfo = Networking.BookingProductInfo
3334
public typealias BookingResource = Networking.BookingResource
35+
public typealias BookingAttendanceStatus = Networking.BookingAttendanceStatus
3436
public typealias CreateBlazeCampaign = Networking.CreateBlazeCampaign
3537
public typealias FallibleCancelable = Hardware.FallibleCancelable
3638
public typealias CommentStatus = Networking.CommentStatus
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import Foundation
2+
import enum WooFoundation.CountryCode
3+
import enum WooFoundation.CurrencyCode
4+
5+
/// Validator for POS country and currency support
6+
/// Single source of truth for supported countries and currencies
7+
public enum POSCountryCurrencyValidator {
8+
/// Supported countries for POS feature
9+
public static let supportedCountries: [CountryCode] = [.US, .GB]
10+
11+
/// Supported currencies per country for POS feature
12+
public static let supportedCurrencies: [CountryCode: [CurrencyCode]] = [
13+
.US: [.USD],
14+
.GB: [.GBP]
15+
]
16+
17+
/// Validates if a country and currency combination is eligible for POS
18+
/// - Parameters:
19+
/// - countryCode: The store's country code
20+
/// - currencyCode: The store's currency code
21+
/// - Returns: Eligibility state with reason if ineligible
22+
public static func validate(countryCode: CountryCode, currencyCode: CurrencyCode) -> ValidationResult {
23+
// Check country first
24+
guard supportedCountries.contains(countryCode) else {
25+
return .ineligible(reason: .unsupportedCountry(supportedCountries: supportedCountries))
26+
}
27+
28+
// Check currency for the country
29+
let supportedCurrenciesForCountry = supportedCurrencies[countryCode] ?? []
30+
guard supportedCurrenciesForCountry.contains(currencyCode) else {
31+
return .ineligible(reason: .unsupportedCurrency(countryCode: countryCode, supportedCurrencies: supportedCurrenciesForCountry))
32+
}
33+
34+
return .eligible
35+
}
36+
}
37+
38+
// MARK: - Validation Result
39+
40+
public extension POSCountryCurrencyValidator {
41+
enum ValidationResult: Equatable {
42+
case eligible
43+
case ineligible(reason: IneligibleReason)
44+
}
45+
46+
enum IneligibleReason: Equatable {
47+
case unsupportedCountry(supportedCountries: [CountryCode])
48+
case unsupportedCurrency(countryCode: CountryCode, supportedCurrencies: [CurrencyCode])
49+
}
50+
}

Modules/Sources/Yosemite/Stores/BookingStore.swift

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,17 @@ public class BookingStore: Store {
6363
onCompletion: onCompletion)
6464
case let .fetchResource(siteID, resourceID, onCompletion):
6565
fetchResource(siteID: siteID, resourceID: resourceID, onCompletion: onCompletion)
66+
case .updateBookingAttendanceStatus(let siteID, let bookingID, let status, let onCompletion):
67+
performUpdateBookingAttendanceStatus(
68+
siteID: siteID,
69+
bookingID: bookingID,
70+
status: status,
71+
onCompletion: onCompletion
72+
)
6673
}
6774
}
6875
}
6976

70-
7177
// MARK: - Services
7278
//
7379
private extension BookingStore {
@@ -246,6 +252,50 @@ private extension BookingStore {
246252
}
247253
}
248254
}
255+
256+
func performUpdateBookingAttendanceStatus(
257+
siteID: Int64,
258+
bookingID: Int64,
259+
status: BookingAttendanceStatus,
260+
onCompletion: @escaping (Error?) -> Void
261+
) {
262+
updateBookingAttendanceStatusLocally(
263+
siteID: siteID,
264+
bookingID: bookingID,
265+
statusKey: status
266+
) { _ in
267+
//TODO: - booking status remote update + rollback status in case of error
268+
onCompletion(nil)
269+
}
270+
}
271+
272+
/// Updates local (Storage) Booking attendance status
273+
func updateBookingAttendanceStatusLocally(
274+
siteID: Int64,
275+
bookingID: Int64,
276+
statusKey: BookingAttendanceStatus,
277+
onCompletion: @escaping (BookingAttendanceStatus) -> Void
278+
) {
279+
storageManager.performAndSave({ storage -> BookingAttendanceStatus in
280+
guard let booking = storage.loadBooking(
281+
siteID: siteID,
282+
bookingID: bookingID
283+
) else {
284+
return statusKey
285+
}
286+
287+
let oldStatus = booking.attendanceStatusKey
288+
booking.attendanceStatusKey = statusKey.rawValue
289+
return BookingAttendanceStatus(rawValue: oldStatus ?? "") ?? .unknown
290+
}, completion: { result in
291+
switch result {
292+
case .success(let status):
293+
onCompletion(status)
294+
case .failure:
295+
onCompletion(statusKey)
296+
}
297+
}, on: .main)
298+
}
249299
}
250300

251301

Modules/Tests/YosemiteTests/Mocks/MockBookingsRemote.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,8 @@ final class MockBookingsRemote: BookingsRemoteProtocol {
4646
}
4747
return try result.get()
4848
}
49+
50+
func updateBooking(from siteID: Int64, bookingID: Int64, attendanceStatus: Networking.BookingAttendanceStatus) async throws -> Networking.Booking? {
51+
return nil
52+
}
4953
}

0 commit comments

Comments
 (0)