diff --git a/Modules/Sources/Networking/Model/Copiable/Models+Copiable.generated.swift b/Modules/Sources/Networking/Model/Copiable/Models+Copiable.generated.swift index f43a26bda9d..68c69a8fbf5 100644 --- a/Modules/Sources/Networking/Model/Copiable/Models+Copiable.generated.swift +++ b/Modules/Sources/Networking/Model/Copiable/Models+Copiable.generated.swift @@ -436,8 +436,8 @@ extension Networking.Booking { allDay: CopiableProp = .copy, cost: CopiableProp = .copy, customerID: CopiableProp = .copy, - dateCreated: CopiableProp = .copy, - dateModified: CopiableProp = .copy, + dateCreated: NullableCopiableProp = .copy, + dateModified: NullableCopiableProp = .copy, endDate: CopiableProp = .copy, googleCalendarEventID: NullableCopiableProp = .copy, orderID: CopiableProp = .copy, diff --git a/Modules/Sources/PointOfSale/Presentation/Settings/POSSettingsLocalCatalogDetailView.swift b/Modules/Sources/PointOfSale/Presentation/Settings/POSSettingsLocalCatalogDetailView.swift index 8176e20da2d..b20de2d5b52 100644 --- a/Modules/Sources/PointOfSale/Presentation/Settings/POSSettingsLocalCatalogDetailView.swift +++ b/Modules/Sources/PointOfSale/Presentation/Settings/POSSettingsLocalCatalogDetailView.swift @@ -2,7 +2,6 @@ import SwiftUI struct POSSettingsLocalCatalogDetailView: View { // TODO: WOOMOB-1335 - implement full sync cellular data setting functionality - @State private var allowFullSyncOnCellular: Bool = true private let viewModel: POSSettingsLocalCatalogViewModel init(viewModel: POSSettingsLocalCatalogViewModel) { @@ -51,11 +50,12 @@ private extension POSSettingsLocalCatalogDetailView { @ViewBuilder var managingDataUsage: some View { + @Bindable var viewModel = viewModel VStack(spacing: POSSpacing.none) { sectionHeaderView(title: Localization.managingDataUsage) VStack(spacing: POSSpacing.medium) { - toggleRowView(label: Localization.allowFullSyncOnCellular, isOn: $allowFullSyncOnCellular) + toggleRowView(label: Localization.allowFullSyncOnCellular, isOn: $viewModel.allowFullSyncOnCellular) } .padding(.bottom, POSPadding.medium) } diff --git a/Modules/Sources/PointOfSale/Presentation/Settings/POSSettingsLocalCatalogViewModel.swift b/Modules/Sources/PointOfSale/Presentation/Settings/POSSettingsLocalCatalogViewModel.swift index f102a0e16a8..e05de53064e 100644 --- a/Modules/Sources/PointOfSale/Presentation/Settings/POSSettingsLocalCatalogViewModel.swift +++ b/Modules/Sources/PointOfSale/Presentation/Settings/POSSettingsLocalCatalogViewModel.swift @@ -1,6 +1,7 @@ import CocoaLumberjackSwift import Yosemite import Foundation +import Storage @Observable final class POSSettingsLocalCatalogViewModel { @@ -14,6 +15,7 @@ final class POSSettingsLocalCatalogViewModel { private let siteID: Int64 private let catalogSettingsService: POSCatalogSettingsServiceProtocol private let catalogSyncCoordinator: POSCatalogSyncCoordinatorProtocol + private let siteSettings: SiteSpecificAppSettingsStoreMethodsProtocol private let dateFormatter: RelativeDateTimeFormatter = { let formatter = RelativeDateTimeFormatter() formatter.dateTimeStyle = .named @@ -21,12 +23,23 @@ final class POSSettingsLocalCatalogViewModel { return formatter }() + var allowFullSyncOnCellular: Bool { + get { + siteSettings.getPOSLocalCatalogCellularDataAllowed(siteID: siteID) + } + set { + siteSettings.setPOSLocalCatalogCellularDataAllowed(siteID: siteID, allowed: newValue) + } + } + init(siteID: Int64, catalogSettingsService: POSCatalogSettingsServiceProtocol, - catalogSyncCoordinator: POSCatalogSyncCoordinatorProtocol) { + catalogSyncCoordinator: POSCatalogSyncCoordinatorProtocol, + siteSettings: SiteSpecificAppSettingsStoreMethodsProtocol? = nil) { self.siteID = siteID self.catalogSettingsService = catalogSettingsService self.catalogSyncCoordinator = catalogSyncCoordinator + self.siteSettings = siteSettings ?? SiteSpecificAppSettingsStoreMethods(fileStorage: PListFileStorage()) } @MainActor diff --git a/Modules/Sources/Storage/Model/Copiable/Models+Copiable.generated.swift b/Modules/Sources/Storage/Model/Copiable/Models+Copiable.generated.swift index 4fbfac0e08a..eadb76ddffe 100644 --- a/Modules/Sources/Storage/Model/Copiable/Models+Copiable.generated.swift +++ b/Modules/Sources/Storage/Model/Copiable/Models+Copiable.generated.swift @@ -127,7 +127,8 @@ extension Storage.GeneralStoreSettings { searchTermsByKey: CopiableProp<[String: [String]]> = .copy, isPOSTabVisible: NullableCopiableProp = .copy, lastPOSOpenedDate: NullableCopiableProp = .copy, - firstPOSCatalogSyncDate: NullableCopiableProp = .copy + firstPOSCatalogSyncDate: NullableCopiableProp = .copy, + syncPOSCatalogOverCellular: CopiableProp = .copy ) -> Storage.GeneralStoreSettings { let storeID = storeID ?? self.storeID let isTelemetryAvailable = isTelemetryAvailable ?? self.isTelemetryAvailable @@ -151,6 +152,7 @@ extension Storage.GeneralStoreSettings { let isPOSTabVisible = isPOSTabVisible ?? self.isPOSTabVisible let lastPOSOpenedDate = lastPOSOpenedDate ?? self.lastPOSOpenedDate let firstPOSCatalogSyncDate = firstPOSCatalogSyncDate ?? self.firstPOSCatalogSyncDate + let syncPOSCatalogOverCellular = syncPOSCatalogOverCellular ?? self.syncPOSCatalogOverCellular return Storage.GeneralStoreSettings( storeID: storeID, @@ -174,7 +176,8 @@ extension Storage.GeneralStoreSettings { searchTermsByKey: searchTermsByKey, isPOSTabVisible: isPOSTabVisible, lastPOSOpenedDate: lastPOSOpenedDate, - firstPOSCatalogSyncDate: firstPOSCatalogSyncDate + firstPOSCatalogSyncDate: firstPOSCatalogSyncDate, + syncPOSCatalogOverCellular: syncPOSCatalogOverCellular ) } } diff --git a/Modules/Sources/Storage/Model/GeneralStoreSettings.swift b/Modules/Sources/Storage/Model/GeneralStoreSettings.swift index f18d8a1e041..97f7d9becc3 100644 --- a/Modules/Sources/Storage/Model/GeneralStoreSettings.swift +++ b/Modules/Sources/Storage/Model/GeneralStoreSettings.swift @@ -94,6 +94,10 @@ public struct GeneralStoreSettings: Codable, Equatable, GeneratedCopiable { /// public var firstPOSCatalogSyncDate: Date? + /// Whether we should sync catalog data over cellular connections for this store + /// + public var syncPOSCatalogOverCellular: Bool + public init(storeID: String? = nil, isTelemetryAvailable: Bool = false, telemetryLastReportedTime: Date? = nil, @@ -115,7 +119,8 @@ public struct GeneralStoreSettings: Codable, Equatable, GeneratedCopiable { searchTermsByKey: [String: [String]] = [:], isPOSTabVisible: Bool? = nil, lastPOSOpenedDate: Date? = nil, - firstPOSCatalogSyncDate: Date? = nil) { + firstPOSCatalogSyncDate: Date? = nil, + syncPOSCatalogOverCellular: Bool = true) { self.storeID = storeID self.isTelemetryAvailable = isTelemetryAvailable self.telemetryLastReportedTime = telemetryLastReportedTime @@ -138,6 +143,7 @@ public struct GeneralStoreSettings: Codable, Equatable, GeneratedCopiable { self.isPOSTabVisible = isPOSTabVisible self.lastPOSOpenedDate = lastPOSOpenedDate self.firstPOSCatalogSyncDate = firstPOSCatalogSyncDate + self.syncPOSCatalogOverCellular = syncPOSCatalogOverCellular } public func erasingSelectedTaxRateID() -> GeneralStoreSettings { @@ -198,6 +204,7 @@ extension GeneralStoreSettings { self.isPOSTabVisible = try container.decodeIfPresent(Bool.self, forKey: .isPOSTabVisible) self.lastPOSOpenedDate = try container.decodeIfPresent(Date.self, forKey: .lastPOSOpenedDate) self.firstPOSCatalogSyncDate = try container.decodeIfPresent(Date.self, forKey: .firstPOSCatalogSyncDate) + self.syncPOSCatalogOverCellular = try container.decodeIfPresent(Bool.self, forKey: .syncPOSCatalogOverCellular) ?? true // Decode new properties with `decodeIfPresent` and provide a default value if necessary. } diff --git a/Modules/Sources/Yosemite/Actions/AppSettingsAction.swift b/Modules/Sources/Yosemite/Actions/AppSettingsAction.swift index b6175bc97f0..f3aea4911a3 100644 --- a/Modules/Sources/Yosemite/Actions/AppSettingsAction.swift +++ b/Modules/Sources/Yosemite/Actions/AppSettingsAction.swift @@ -414,4 +414,11 @@ public enum AppSettingsAction: Action { /// Gets the date of the first POS catalog sync for a specific site /// case getFirstPOSCatalogSyncDate(siteID: Int64, onCompletion: (Date?) -> Void) + + /// Sets whether we should allow cellular data use downloading POS catalogs for a specific site + /// + case setPOSLocalCatalogCellularDataAllowed(siteID: Int64, allowed: Bool, onCompletion: () -> Void) + + /// Gets whether we should allow cellular data use downloading POS catalogs for a specific site + case getPOSLocalCatalogCellularDataAllowed(siteID: Int64, onCompletion: (Bool) -> Void) } diff --git a/Modules/Sources/Yosemite/Stores/AppSettingsStore.swift b/Modules/Sources/Yosemite/Stores/AppSettingsStore.swift index ff1344b82a5..2a4daba0fff 100644 --- a/Modules/Sources/Yosemite/Stores/AppSettingsStore.swift +++ b/Modules/Sources/Yosemite/Stores/AppSettingsStore.swift @@ -315,6 +315,10 @@ public class AppSettingsStore: Store { setFirstPOSCatalogSyncDate(siteID: siteID, date: date, onCompletion: onCompletion) case .getFirstPOSCatalogSyncDate(siteID: let siteID, onCompletion: let onCompletion): getFirstPOSCatalogSyncDate(siteID: siteID, onCompletion: onCompletion) + case .setPOSLocalCatalogCellularDataAllowed(let siteID, let allowed, let onCompletion): + setPOSLocalCatalogCellularDataAllowed(siteID: siteID, allowed: allowed, onCompletion: onCompletion) + case .getPOSLocalCatalogCellularDataAllowed(let siteID, let onCompletion): + getPOSLocalCatalogCellularDataAllowed(siteID: siteID, onCompletion: onCompletion) } } } @@ -1365,7 +1369,10 @@ private extension AppSettingsStore { onCompletion(.failure(error)) } } +} +// MARK: - Point of Sale local catalog settings +private extension AppSettingsStore { func setPOSLastOpenedDate(siteID: Int64, date: Date, onCompletion: () -> Void) { siteSpecificAppSettingsStoreMethods.setPOSLastOpenedDate(siteID: siteID, date: date) onCompletion() @@ -1385,6 +1392,16 @@ private extension AppSettingsStore { let date = siteSpecificAppSettingsStoreMethods.getFirstPOSCatalogSyncDate(siteID: siteID) onCompletion(date) } + + func setPOSLocalCatalogCellularDataAllowed(siteID: Int64, allowed: Bool, onCompletion: () -> Void) { + siteSpecificAppSettingsStoreMethods.setPOSLocalCatalogCellularDataAllowed(siteID: siteID, allowed: allowed) + onCompletion() + } + + func getPOSLocalCatalogCellularDataAllowed(siteID: Int64, onCompletion: (Bool) -> Void) { + let allowed = siteSpecificAppSettingsStoreMethods.getPOSLocalCatalogCellularDataAllowed(siteID: siteID) + onCompletion(allowed) + } } // MARK: - Errors diff --git a/Modules/Sources/Yosemite/Stores/Helpers/SiteSpecificAppSettingsStoreMethods.swift b/Modules/Sources/Yosemite/Stores/Helpers/SiteSpecificAppSettingsStoreMethods.swift index 762d8649f2d..1b9f307b35d 100644 --- a/Modules/Sources/Yosemite/Stores/Helpers/SiteSpecificAppSettingsStoreMethods.swift +++ b/Modules/Sources/Yosemite/Stores/Helpers/SiteSpecificAppSettingsStoreMethods.swift @@ -17,11 +17,15 @@ public protocol SiteSpecificAppSettingsStoreMethodsProtocol { func setPOSLastOpenedDate(siteID: Int64, date: Date) func getFirstPOSCatalogSyncDate(siteID: Int64) -> Date? func setFirstPOSCatalogSyncDate(siteID: Int64, date: Date) + + // POS local catalog cellular data + func setPOSLocalCatalogCellularDataAllowed(siteID: Int64, allowed: Bool) + func getPOSLocalCatalogCellularDataAllowed(siteID: Int64) -> Bool } /// Methods for managing site-specific app settings /// -struct SiteSpecificAppSettingsStoreMethods: SiteSpecificAppSettingsStoreMethodsProtocol { +public struct SiteSpecificAppSettingsStoreMethods: SiteSpecificAppSettingsStoreMethodsProtocol { private let fileStorage: FileStorage private let generalStoreSettingsFileURL: URL @@ -40,7 +44,7 @@ struct SiteSpecificAppSettingsStoreMethods: SiteSpecificAppSettingsStoreMethodsP // MARK: - Store Settings extension SiteSpecificAppSettingsStoreMethods { - func getStoreSettings(for siteID: Int64) -> GeneralStoreSettings { + public func getStoreSettings(for siteID: Int64) -> GeneralStoreSettings { guard let existingData: GeneralStoreSettingsBySite = try? fileStorage.data(for: generalStoreSettingsFileURL), let storeSettings = existingData.storeSettingsBySite[siteID] else { return GeneralStoreSettings() @@ -49,7 +53,7 @@ extension SiteSpecificAppSettingsStoreMethods { return storeSettings } - func setStoreSettings(settings: GeneralStoreSettings, for siteID: Int64, onCompletion: ((Result) -> Void)? = nil) { + public func setStoreSettings(settings: GeneralStoreSettings, for siteID: Int64, onCompletion: ((Result) -> Void)? = nil) { var storeSettingsBySite: [Int64: GeneralStoreSettings] = [:] if let existingData: GeneralStoreSettingsBySite = try? fileStorage.data(for: generalStoreSettingsFileURL) { storeSettingsBySite = existingData.storeSettingsBySite @@ -66,7 +70,7 @@ extension SiteSpecificAppSettingsStoreMethods { } } - func resetStoreSettings() { + public func resetStoreSettings() { do { try fileStorage.deleteFile(at: generalStoreSettingsFileURL) } catch { @@ -74,13 +78,13 @@ extension SiteSpecificAppSettingsStoreMethods { } } - func setStoreID(siteID: Int64, id: String?) { + public func setStoreID(siteID: Int64, id: String?) { let storeSettings = getStoreSettings(for: siteID) let updatedSettings = storeSettings.copy(storeID: id) setStoreSettings(settings: updatedSettings, for: siteID) } - func getStoreID(siteID: Int64, onCompletion: (String?) -> Void) { + public func getStoreID(siteID: Int64, onCompletion: (String?) -> Void) { let storeSettings = getStoreSettings(for: siteID) onCompletion(storeSettings.storeID) } @@ -88,13 +92,13 @@ extension SiteSpecificAppSettingsStoreMethods { // MARK: - Search History extension SiteSpecificAppSettingsStoreMethods { - func getSearchTerms(for itemType: POSItemType, siteID: Int64) -> [String] { + public func getSearchTerms(for itemType: POSItemType, siteID: Int64) -> [String] { let storeSettings = getStoreSettings(for: siteID) let key = itemType.storedSearchHistoryKey return storeSettings.searchTermsByKey[key] ?? [] } - func setSearchTerms(_ terms: [String], for itemType: POSItemType, siteID: Int64) { + public func setSearchTerms(_ terms: [String], for itemType: POSItemType, siteID: Int64) { let storeSettings = getStoreSettings(for: siteID) let key = itemType.storedSearchHistoryKey var updatedSearchTermsByKey = storeSettings.searchTermsByKey @@ -102,28 +106,44 @@ extension SiteSpecificAppSettingsStoreMethods { let updatedSettings = storeSettings.copy(searchTermsByKey: updatedSearchTermsByKey) setStoreSettings(settings: updatedSettings, for: siteID) } +} - func getPOSLastOpenedDate(siteID: Int64) -> Date? { +// MARK: - POS sync eligibility tracking +extension SiteSpecificAppSettingsStoreMethods { + public func getPOSLastOpenedDate(siteID: Int64) -> Date? { getStoreSettings(for: siteID).lastPOSOpenedDate } - func setPOSLastOpenedDate(siteID: Int64, date: Date) { + public func setPOSLastOpenedDate(siteID: Int64, date: Date) { let storeSettings = getStoreSettings(for: siteID) let updatedSettings = storeSettings.copy(lastPOSOpenedDate: date) setStoreSettings(settings: updatedSettings, for: siteID) } - func getFirstPOSCatalogSyncDate(siteID: Int64) -> Date? { + public func getFirstPOSCatalogSyncDate(siteID: Int64) -> Date? { getStoreSettings(for: siteID).firstPOSCatalogSyncDate } - func setFirstPOSCatalogSyncDate(siteID: Int64, date: Date) { + public func setFirstPOSCatalogSyncDate(siteID: Int64, date: Date) { let storeSettings = getStoreSettings(for: siteID) let updatedSettings = storeSettings.copy(firstPOSCatalogSyncDate: date) setStoreSettings(settings: updatedSettings, for: siteID) } } +// MARK: - POS local catalog cellular data +extension SiteSpecificAppSettingsStoreMethods { + public func setPOSLocalCatalogCellularDataAllowed(siteID: Int64, allowed: Bool) { + let storeSettings = getStoreSettings(for: siteID) + let updatedSettings = storeSettings.copy(syncPOSCatalogOverCellular: allowed) + setStoreSettings(settings: updatedSettings, for: siteID) + } + + public func getPOSLocalCatalogCellularDataAllowed(siteID: Int64) -> Bool { + getStoreSettings(for: siteID).syncPOSCatalogOverCellular + } +} + // MARK: - Constants private enum Constants { static let generalStoreSettingsFileName = "general-store-settings.plist" diff --git a/Modules/Tests/PointOfSaleTests/Mocks/MockSiteSpecificAppSettingsStoreMethods.swift b/Modules/Tests/PointOfSaleTests/Mocks/MockSiteSpecificAppSettingsStoreMethods.swift new file mode 100644 index 00000000000..39ceab484ac --- /dev/null +++ b/Modules/Tests/PointOfSaleTests/Mocks/MockSiteSpecificAppSettingsStoreMethods.swift @@ -0,0 +1,60 @@ +@testable import Yosemite +import Foundation +import Storage + +/// Minimal mock for SiteSpecificAppSettingsStoreMethodsProtocol +/// Only implements the methods needed for POS local catalog tests +final class MockSiteSpecificAppSettingsStoreMethods: SiteSpecificAppSettingsStoreMethodsProtocol { + var currentSiteID: Int64 = 1 + + // POS local catalog cellular data properties + var getPOSLocalCatalogCellularDataAllowedCalled = false + var setPOSLocalCatalogCellularDataAllowedCalled = false + var mockPOSLocalCatalogCellularDataAllowed: Bool? + + // Implement only the methods we actually use + func setPOSLocalCatalogCellularDataAllowed(siteID: Int64, allowed: Bool) { + setPOSLocalCatalogCellularDataAllowedCalled = true + mockPOSLocalCatalogCellularDataAllowed = allowed + } + + func getPOSLocalCatalogCellularDataAllowed(siteID: Int64) -> Bool { + getPOSLocalCatalogCellularDataAllowedCalled = true + return mockPOSLocalCatalogCellularDataAllowed ?? false + } + + // Protocol requirements - minimal implementations + func getStoreSettings(for siteID: Int64) -> GeneralStoreSettings { + GeneralStoreSettings() + } + + func setStoreSettings(settings: GeneralStoreSettings, for siteID: Int64, onCompletion: ((Result) -> Void)?) { + onCompletion?(.success(())) + } + + func resetStoreSettings() {} + + func setStoreID(siteID: Int64, id: String?) {} + + func getStoreID(siteID: Int64, onCompletion: (String?) -> Void) { + onCompletion(nil) + } + + func getSearchTerms(for itemType: POSItemType, siteID: Int64) -> [String] { + [] + } + + func setSearchTerms(_ terms: [String], for itemType: POSItemType, siteID: Int64) {} + + func getPOSLastOpenedDate(siteID: Int64) -> Date? { + nil + } + + func setPOSLastOpenedDate(siteID: Int64, date: Date) {} + + func getFirstPOSCatalogSyncDate(siteID: Int64) -> Date? { + nil + } + + func setFirstPOSCatalogSyncDate(siteID: Int64, date: Date) {} +} diff --git a/Modules/Tests/PointOfSaleTests/Presentation/Settings/POSSettingsLocalCatalogViewModelTests.swift b/Modules/Tests/PointOfSaleTests/Presentation/Settings/POSSettingsLocalCatalogViewModelTests.swift index fbcfae44173..e843cc49bb1 100644 --- a/Modules/Tests/PointOfSaleTests/Presentation/Settings/POSSettingsLocalCatalogViewModelTests.swift +++ b/Modules/Tests/PointOfSaleTests/Presentation/Settings/POSSettingsLocalCatalogViewModelTests.swift @@ -8,14 +8,18 @@ struct POSSettingsLocalCatalogViewModelTests { private let sut: POSSettingsLocalCatalogViewModel private let catalogSettingsService: MockPOSCatalogSettingsService private let catalogSyncCoordinator: MockPOSCatalogSyncCoordinator + private let siteSettings: MockSiteSpecificAppSettingsStoreMethods init() { self.catalogSettingsService = MockPOSCatalogSettingsService() self.catalogSyncCoordinator = MockPOSCatalogSyncCoordinator() + self.siteSettings = MockSiteSpecificAppSettingsStoreMethods() + self.siteSettings.currentSiteID = sampleSiteID self.sut = POSSettingsLocalCatalogViewModel( siteID: sampleSiteID, catalogSettingsService: catalogSettingsService, - catalogSyncCoordinator: catalogSyncCoordinator + catalogSyncCoordinator: catalogSyncCoordinator, + siteSettings: siteSettings ) } @@ -199,6 +203,49 @@ struct POSSettingsLocalCatalogViewModelTests { #expect(sut.isRefreshingCatalog == false) #expect(catalogSyncCoordinator.performFullSyncInvocationCount == 1) } + + // MARK: - allowFullSyncOnCellular Tests + + @Test func allowFullSyncOnCellular_returns_default_value_from_site_settings() async throws { + // Given + siteSettings.mockPOSLocalCatalogCellularDataAllowed = false + + // When + let isAllowed = sut.allowFullSyncOnCellular + + // Then + #expect(isAllowed == false) + #expect(siteSettings.getPOSLocalCatalogCellularDataAllowedCalled == true) + } + + @Test func allowFullSyncOnCellular_setter_updates_site_settings() async throws { + // When + sut.allowFullSyncOnCellular = true + + // Then + #expect(siteSettings.setPOSLocalCatalogCellularDataAllowedCalled == true) + #expect(siteSettings.mockPOSLocalCatalogCellularDataAllowed == true) + } + + @Test func allowFullSyncOnCellular_getter_and_setter_work_as_two_way_binding() async throws { + // Given - Initially false + siteSettings.mockPOSLocalCatalogCellularDataAllowed = false + #expect(sut.allowFullSyncOnCellular == false) + + // When - Set to true + sut.allowFullSyncOnCellular = true + + // Then - Value is persisted and can be retrieved + #expect(siteSettings.mockPOSLocalCatalogCellularDataAllowed == true) + #expect(sut.allowFullSyncOnCellular == true) + + // When - Set to false + sut.allowFullSyncOnCellular = false + + // Then - Value is persisted and can be retrieved + #expect(siteSettings.mockPOSLocalCatalogCellularDataAllowed == false) + #expect(sut.allowFullSyncOnCellular == false) + } } private enum MockError: Error { diff --git a/Modules/Tests/YosemiteTests/Mocks/MockSiteSpecificAppSettingsStoreMethods.swift b/Modules/Tests/YosemiteTests/Mocks/MockSiteSpecificAppSettingsStoreMethods.swift index 45f6846238a..6daffa6de9c 100644 --- a/Modules/Tests/YosemiteTests/Mocks/MockSiteSpecificAppSettingsStoreMethods.swift +++ b/Modules/Tests/YosemiteTests/Mocks/MockSiteSpecificAppSettingsStoreMethods.swift @@ -35,6 +35,9 @@ final class MockSiteSpecificAppSettingsStoreMethods: SiteSpecificAppSettingsStor var setFirstPOSCatalogSyncDateCalled = false var mockPOSLastOpenedDate: Date? var mockFirstPOSCatalogSyncDate: Date? + var getPOSLocalCatalogCellularDataAllowedCalled = false + var setPOSLocalCatalogCellularDataAllowedCalled = false + var mockPOSLocalCatalogCellularDataAllowed: Bool? func getStoreSettings(for siteID: Int64) -> GeneralStoreSettings { @@ -114,4 +117,14 @@ final class MockSiteSpecificAppSettingsStoreMethods: SiteSpecificAppSettingsStor setFirstPOSCatalogSyncDateCalled = true mockFirstPOSCatalogSyncDate = date } + + func setPOSLocalCatalogCellularDataAllowed(siteID: Int64, allowed: Bool) { + setPOSLocalCatalogCellularDataAllowedCalled = true + mockPOSLocalCatalogCellularDataAllowed = allowed + } + + func getPOSLocalCatalogCellularDataAllowed(siteID: Int64) -> Bool { + getPOSLocalCatalogCellularDataAllowedCalled = true + return mockPOSLocalCatalogCellularDataAllowed ?? false + } } diff --git a/Modules/Tests/YosemiteTests/Stores/AppSettingsStoreTests.swift b/Modules/Tests/YosemiteTests/Stores/AppSettingsStoreTests.swift index 3253db0802c..49ee9470557 100644 --- a/Modules/Tests/YosemiteTests/Stores/AppSettingsStoreTests.swift +++ b/Modules/Tests/YosemiteTests/Stores/AppSettingsStoreTests.swift @@ -1736,6 +1736,69 @@ extension AppSettingsStoreTests { } XCTAssertFalse(checkPOSOpenedAfterReset) } + + // MARK: - POS Local Catalog Cellular Data Tests + + func test_getPOSLocalCatalogCellularDataAllowed_returns_false_by_default() throws { + // When + let isAllowed: Bool = waitFor { promise in + let action = AppSettingsAction.getPOSLocalCatalogCellularDataAllowed(siteID: TestConstants.siteID) { isAllowed in + promise(isAllowed) + } + self.subject?.onAction(action) + } + + // Then + XCTAssertFalse(isAllowed) + } + + func test_getPOSLocalCatalogCellularDataAllowed_returns_saved_value() throws { + // Given + mockSiteSpecificAppSettingsStoreMethods.mockPOSLocalCatalogCellularDataAllowed = true + + // When + let isAllowed: Bool = waitFor { promise in + let action = AppSettingsAction.getPOSLocalCatalogCellularDataAllowed(siteID: TestConstants.siteID) { isAllowed in + promise(isAllowed) + } + self.subject?.onAction(action) + } + + // Then + XCTAssertTrue(mockSiteSpecificAppSettingsStoreMethods.getPOSLocalCatalogCellularDataAllowedCalled) + XCTAssertTrue(isAllowed) + } + + func test_setPOSLocalCatalogCellularDataAllowed_saves_value_successfully() throws { + // When + waitFor { promise in + let action = AppSettingsAction.setPOSLocalCatalogCellularDataAllowed(siteID: TestConstants.siteID, allowed: true) { + promise(()) + } + self.subject?.onAction(action) + } + + // Then + XCTAssertTrue(mockSiteSpecificAppSettingsStoreMethods.setPOSLocalCatalogCellularDataAllowedCalled) + XCTAssertEqual(mockSiteSpecificAppSettingsStoreMethods.mockPOSLocalCatalogCellularDataAllowed, true) + } + + func test_setPOSLocalCatalogCellularDataAllowed_can_set_false() throws { + // Given + mockSiteSpecificAppSettingsStoreMethods.mockPOSLocalCatalogCellularDataAllowed = true + + // When + waitFor { promise in + let action = AppSettingsAction.setPOSLocalCatalogCellularDataAllowed(siteID: TestConstants.siteID, allowed: false) { + promise(()) + } + self.subject?.onAction(action) + } + + // Then + XCTAssertTrue(mockSiteSpecificAppSettingsStoreMethods.setPOSLocalCatalogCellularDataAllowedCalled) + XCTAssertEqual(mockSiteSpecificAppSettingsStoreMethods.mockPOSLocalCatalogCellularDataAllowed, false) + } } // MARK: - Utils diff --git a/Modules/Tests/YosemiteTests/Stores/Helpers/SiteSpecificAppSettingsStoreMethodsTests.swift b/Modules/Tests/YosemiteTests/Stores/Helpers/SiteSpecificAppSettingsStoreMethodsTests.swift index 164649dcab1..4c784c447bd 100644 --- a/Modules/Tests/YosemiteTests/Stores/Helpers/SiteSpecificAppSettingsStoreMethodsTests.swift +++ b/Modules/Tests/YosemiteTests/Stores/Helpers/SiteSpecificAppSettingsStoreMethodsTests.swift @@ -230,6 +230,74 @@ struct SiteSpecificAppSettingsStoreMethodsTests { #expect(retrievedCouponTerms == couponTerms) } + // MARK: - POS Local Catalog Cellular Data Tests + + @Test func getPOSLocalCatalogCellularDataAllowed_returns_true_by_default() { + // When + let isAllowed = sut.getPOSLocalCatalogCellularDataAllowed(siteID: siteID) + + // Then + #expect(isAllowed == true) + } + + @Test func getPOSLocalCatalogCellularDataAllowed_returns_saved_value() throws { + // Given + let storeSettings = GeneralStoreSettings(syncPOSCatalogOverCellular: false) + let existingData = GeneralStoreSettingsBySite(storeSettingsBySite: [siteID: storeSettings]) + try fileStorage.write(existingData, to: SiteSpecificAppSettingsStoreMethods.defaultGeneralStoreSettingsFileURL) + + // When + let isAllowed = sut.getPOSLocalCatalogCellularDataAllowed(siteID: siteID) + + // Then + #expect(isAllowed == false) + } + + @Test func setPOSLocalCatalogCellularDataAllowed_saves_value_successfully() throws { + // Given + let existingSettings = GeneralStoreSettingsBySite(storeSettingsBySite: [siteID: GeneralStoreSettings()]) + try fileStorage.write(existingSettings, to: SiteSpecificAppSettingsStoreMethods.defaultGeneralStoreSettingsFileURL) + + // When + sut.setPOSLocalCatalogCellularDataAllowed(siteID: siteID, allowed: false) + + // Then + let savedData: GeneralStoreSettingsBySite = try fileStorage.data(for: SiteSpecificAppSettingsStoreMethods.defaultGeneralStoreSettingsFileURL) + #expect(savedData.storeSettingsBySite[siteID]?.syncPOSCatalogOverCellular == false) + } + + @Test func setPOSLocalCatalogCellularDataAllowed_preserves_existing_settings() throws { + // Given + let existingStoreID = "existing-store-id" + let existingSettings = GeneralStoreSettings(storeID: existingStoreID) + let existingData = GeneralStoreSettingsBySite(storeSettingsBySite: [siteID: existingSettings]) + try fileStorage.write(existingData, to: SiteSpecificAppSettingsStoreMethods.defaultGeneralStoreSettingsFileURL) + + // When + sut.setPOSLocalCatalogCellularDataAllowed(siteID: siteID, allowed: false) + + // Then + let savedData: GeneralStoreSettingsBySite = try fileStorage.data(for: SiteSpecificAppSettingsStoreMethods.defaultGeneralStoreSettingsFileURL) + #expect(savedData.storeSettingsBySite[siteID]?.syncPOSCatalogOverCellular == false) + #expect(savedData.storeSettingsBySite[siteID]?.storeID == existingStoreID) + } + + @Test func setPOSLocalCatalogCellularDataAllowed_preserves_settings_for_other_sites() throws { + // Given + let otherSiteID: Int64 = 456 + let otherSiteSettings = GeneralStoreSettings(syncPOSCatalogOverCellular: true) + let existingData = GeneralStoreSettingsBySite(storeSettingsBySite: [otherSiteID: otherSiteSettings]) + try fileStorage.write(existingData, to: SiteSpecificAppSettingsStoreMethods.defaultGeneralStoreSettingsFileURL) + + // When + sut.setPOSLocalCatalogCellularDataAllowed(siteID: siteID, allowed: false) + + // Then + let savedData: GeneralStoreSettingsBySite = try fileStorage.data(for: SiteSpecificAppSettingsStoreMethods.defaultGeneralStoreSettingsFileURL) + #expect(savedData.storeSettingsBySite[siteID]?.syncPOSCatalogOverCellular == false) + #expect(savedData.storeSettingsBySite[otherSiteID]?.syncPOSCatalogOverCellular == true) + } + } // MARK: - Mock FileStorage