Skip to content

Commit 835331a

Browse files
committed
Move SettingsStore methods to SettingsStoreMethods to use them independently within Yosemite
1 parent f97ec02 commit 835331a

File tree

3 files changed

+260
-217
lines changed

3 files changed

+260
-217
lines changed

Yosemite/Yosemite.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
012848DC2D9ED55B00A9C69B /* SettingStoreMethods.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012848DB2D9ED55700A9C69B /* SettingStoreMethods.swift */; };
1011
0139C2B02D91D1C600C78FDE /* POSCart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0139C2AF2D91D1C400C78FDE /* POSCart.swift */; };
1112
016A776B2D9D30C90004FCD6 /* PointOfSaleCouponServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 016A776A2D9D30C10004FCD6 /* PointOfSaleCouponServiceTests.swift */; };
1213
016A89D82D9D6DB50004FCD6 /* CouponStoreMethods.swift in Sources */ = {isa = PBXBuildFile; fileRef = 016A89D72D9D6DAE0004FCD6 /* CouponStoreMethods.swift */; };
@@ -556,6 +557,7 @@
556557
/* End PBXCopyFilesBuildPhase section */
557558

558559
/* Begin PBXFileReference section */
560+
012848DB2D9ED55700A9C69B /* SettingStoreMethods.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingStoreMethods.swift; sourceTree = "<group>"; };
559561
0139C2AF2D91D1C400C78FDE /* POSCart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = POSCart.swift; sourceTree = "<group>"; };
560562
016A776A2D9D30C10004FCD6 /* PointOfSaleCouponServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PointOfSaleCouponServiceTests.swift; sourceTree = "<group>"; };
561563
016A89D72D9D6DAE0004FCD6 /* CouponStoreMethods.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CouponStoreMethods.swift; sourceTree = "<group>"; };
@@ -1118,6 +1120,7 @@
11181120
016A89D42D9D6D980004FCD6 /* Helpers */ = {
11191121
isa = PBXGroup;
11201122
children = (
1123+
012848DB2D9ED55700A9C69B /* SettingStoreMethods.swift */,
11211124
016A89D72D9D6DAE0004FCD6 /* CouponStoreMethods.swift */,
11221125
);
11231126
path = Helpers;
@@ -2629,6 +2632,7 @@
26292632
B93E03282A960CAD009CA9C1 /* TaxBasedOnSetting.swift in Sources */,
26302633
CE12FBDB221F406100C59248 /* OrderStatus+ReadOnlyConvertible.swift in Sources */,
26312634
74D42DBC221C983F00B4977D /* ShipmentTracking+ReadOnlyConvertible.swift in Sources */,
2635+
012848DC2D9ED55B00A9C69B /* SettingStoreMethods.swift in Sources */,
26322636
247CE87A258332B400F9D9D1 /* MockNotificationActionHandler.swift in Sources */,
26332637
CCCF3A8129C07DD9001D3507 /* ProductBundleItem+ReadOnlyConvertible.swift in Sources */,
26342638
B9AECD3E2850F41100E78584 /* OrderCardPresentPaymentEligibilityAction.swift in Sources */,
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
import Foundation
2+
import Networking
3+
import Storage
4+
5+
/// SettingStoreMethods extracts functionality of SettingStore that needs be reused within Yosemite
6+
/// SettingStoreMethods is intentionally internal not to be exposed outside the module
7+
///
8+
internal protocol SettingStoreMethodsProtocol {
9+
func synchronizeGeneralSiteSettings(siteID: Int64, onCompletion: @escaping (Error?) -> Void)
10+
func synchronizeProductSiteSettings(siteID: Int64, onCompletion: @escaping (Error?) -> Void)
11+
func retrieveSiteAPI(siteID: Int64, onCompletion: @escaping (Result<SiteAPI, Error>) -> Void)
12+
func retrieveCouponSetting(siteID: Int64, onCompletion: @escaping (Result<Bool, Error>) -> Void)
13+
func enableCouponSetting(siteID: Int64, onCompletion: @escaping (Result<Void, Error>) -> Void)
14+
func retrieveAnalyticsSetting(siteID: Int64, onCompletion: @escaping (Result<Bool, Error>) -> Void)
15+
func enableAnalyticsSetting(siteID: Int64, onCompletion: @escaping (Result<Void, Error>) -> Void)
16+
func retrieveTaxBasedOnSetting(siteID: Int64, onCompletion: @escaping (Result<TaxBasedOnSetting, Error>) -> Void)
17+
}
18+
19+
internal class SettingStoreMethods: SettingStoreMethodsProtocol {
20+
private let siteSettingsRemote: SiteSettingsRemote
21+
private let siteAPIRemote: SiteAPIRemote
22+
private let storageManager: StorageManagerType
23+
private let network: Network
24+
25+
init(storageManager: StorageManagerType, network: Network) {
26+
self.siteSettingsRemote = SiteSettingsRemote(network: network)
27+
self.siteAPIRemote = SiteAPIRemote(network: network)
28+
self.network = network
29+
self.storageManager = storageManager
30+
}
31+
32+
/// Synchronizes the general site settings associated with the provided Site ID (if any!).
33+
///
34+
func synchronizeGeneralSiteSettings(siteID: Int64, onCompletion: @escaping (Error?) -> Void) {
35+
siteSettingsRemote.loadGeneralSettings(for: siteID) { [weak self] (settings, error) in
36+
guard let settings = settings else {
37+
onCompletion(error)
38+
return
39+
}
40+
41+
self?.upsertStoredGeneralSettingsInBackground(siteID: siteID, readOnlySiteSettings: settings) {
42+
onCompletion(nil)
43+
}
44+
}
45+
}
46+
47+
/// Synchronizes the product site settings associated with the provided Site ID (if any!).
48+
///
49+
func synchronizeProductSiteSettings(siteID: Int64, onCompletion: @escaping (Error?) -> Void) {
50+
siteSettingsRemote.loadProductSettings(for: siteID) { [weak self] (settings, error) in
51+
guard let settings = settings else {
52+
onCompletion(error)
53+
return
54+
}
55+
56+
self?.upsertStoredProductSettingsInBackground(siteID: siteID, readOnlySiteSettings: settings) {
57+
onCompletion(nil)
58+
}
59+
}
60+
}
61+
62+
/// Retrieves the site API information associated with the provided Site ID (if any!).
63+
/// This call does NOT persist returned data into the Storage layer.
64+
///
65+
func retrieveSiteAPI(siteID: Int64, onCompletion: @escaping (Result<SiteAPI, Error>) -> Void) {
66+
siteAPIRemote.loadAPIInformation(for: siteID, completion: onCompletion)
67+
}
68+
69+
/// Retrieves the setting for whether coupons are enabled for the specified store
70+
///
71+
func retrieveCouponSetting(siteID: Int64, onCompletion: @escaping (Result<Bool, Error>) -> Void) {
72+
siteSettingsRemote.loadSetting(for: siteID, settingGroup: .general, settingID: SettingKeys.coupons) { [weak self] result in
73+
guard let self = self else { return }
74+
switch result {
75+
case .success(let setting):
76+
self.upsertStoredGeneralSettingsInBackground(siteID: siteID, readOnlySiteSettings: [setting]) {
77+
let isEnabled = setting.value == SettingValue.yes
78+
onCompletion(.success(isEnabled))
79+
}
80+
case .failure(let error):
81+
onCompletion(.failure(error))
82+
}
83+
}
84+
}
85+
86+
/// Enables coupons for the specified store
87+
///
88+
func enableCouponSetting(siteID: Int64, onCompletion: @escaping (Result<Void, Error>) -> Void) {
89+
siteSettingsRemote.updateSetting(for: siteID, settingGroup: .general, settingID: SettingKeys.coupons, value: SettingValue.yes) { [weak self] result in
90+
guard let self = self else { return }
91+
switch result {
92+
case .success(let setting):
93+
self.upsertStoredGeneralSettingsInBackground(siteID: siteID, readOnlySiteSettings: [setting]) {
94+
onCompletion(.success(Void()))
95+
}
96+
case .failure(let error):
97+
onCompletion(.failure(error))
98+
}
99+
}
100+
}
101+
102+
/// Retrieves the setting for whether WC Analytics are enabled for the specified store
103+
///
104+
func retrieveAnalyticsSetting(siteID: Int64, onCompletion: @escaping (Result<Bool, Error>) -> Void) {
105+
siteSettingsRemote.loadSetting(for: siteID, settingGroup: .advanced, settingID: SettingKeys.analytics) { [weak self] result in
106+
guard let self = self else { return }
107+
switch result {
108+
case .success(let setting):
109+
self.upsertStoredAdvancedSettingsInBackground(siteID: siteID, readOnlySiteSettings: [setting]) {
110+
let isEnabled = setting.value == SettingValue.yes
111+
onCompletion(.success(isEnabled))
112+
}
113+
case .failure(let error):
114+
onCompletion(.failure(error))
115+
}
116+
}
117+
}
118+
119+
/// Enables WC Analytics for the specified store
120+
///
121+
func enableAnalyticsSetting(siteID: Int64, onCompletion: @escaping (Result<Void, Error>) -> Void) {
122+
siteSettingsRemote.updateSetting(for: siteID,
123+
settingGroup: .advanced,
124+
settingID: SettingKeys.analytics,
125+
value: SettingValue.yes) { [weak self] result in
126+
guard let self = self else { return }
127+
switch result {
128+
case .success(let setting):
129+
self.upsertStoredAdvancedSettingsInBackground(siteID: siteID, readOnlySiteSettings: [setting]) {
130+
onCompletion(.success(Void()))
131+
}
132+
case .failure(let error):
133+
onCompletion(.failure(error))
134+
}
135+
}
136+
}
137+
138+
/// Retrieves the used address to calculate the tax
139+
///
140+
func retrieveTaxBasedOnSetting(siteID: Int64, onCompletion: @escaping (Result<TaxBasedOnSetting, Error>) -> Void) {
141+
siteSettingsRemote.loadSetting(for: siteID, settingGroup: .custom("tax"), settingID: SettingKeys.taxBasedOn) { [weak self] result in
142+
guard let self = self else { return }
143+
switch result {
144+
case .success(let setting):
145+
self.upsertStoredAdvancedSettingsInBackground(siteID: siteID, readOnlySiteSettings: [setting]) {
146+
guard let taxBasedOnSetting = TaxBasedOnSetting(backendValue: setting.value) else {
147+
onCompletion(.failure(SettingError.parseError))
148+
return
149+
}
150+
151+
onCompletion(.success(taxBasedOnSetting))
152+
}
153+
case .failure(let error):
154+
onCompletion(.failure(error))
155+
}
156+
}
157+
}
158+
}
159+
160+
// MARK: - Persistence
161+
162+
private extension SettingStoreMethods {
163+
164+
/// Updates (OR Inserts) the specified **general** ReadOnly `SiteSetting` Entities **in a background thread**. `onCompletion` will be called
165+
/// on the main thread!
166+
///
167+
func upsertStoredGeneralSettingsInBackground(siteID: Int64, readOnlySiteSettings: [Networking.SiteSetting], onCompletion: @escaping () -> Void) {
168+
storageManager.performAndSave({ [weak self] storage in
169+
self?.upsertSettings(readOnlySiteSettings, in: storage, siteID: siteID, settingGroup: SiteSettingGroup.general)
170+
}, completion: onCompletion, on: .main)
171+
}
172+
173+
/// Updates (OR Inserts) the specified **product** ReadOnly `SiteSetting` entities **in a background thread**. `onCompletion` will be called
174+
/// on the main thread!
175+
///
176+
func upsertStoredProductSettingsInBackground(siteID: Int64, readOnlySiteSettings: [Networking.SiteSetting], onCompletion: @escaping () -> Void) {
177+
storageManager.performAndSave({ [weak self] storage in
178+
self?.upsertSettings(readOnlySiteSettings, in: storage, siteID: siteID, settingGroup: SiteSettingGroup.product)
179+
}, completion: onCompletion, on: .main)
180+
}
181+
182+
/// Updates (OR Inserts) the specified **advanced** ReadOnly `SiteSetting` entities **in a background thread**. `onCompletion` will be called
183+
/// on the main thread!
184+
///
185+
func upsertStoredAdvancedSettingsInBackground(siteID: Int64, readOnlySiteSettings: [Networking.SiteSetting], onCompletion: @escaping () -> Void) {
186+
storageManager.performAndSave({ [weak self] storage in
187+
self?.upsertSettings(readOnlySiteSettings, in: storage, siteID: siteID, settingGroup: SiteSettingGroup.advanced)
188+
}, completion: onCompletion, on: .main)
189+
}
190+
191+
func upsertSettings(_ readOnlySiteSettings: [SiteSetting], in storage: StorageType, siteID: Int64, settingGroup: SiteSettingGroup) {
192+
let storageSiteSettings = storage.loadSiteSettings(siteID: siteID, settingGroupKey: settingGroup.rawValue)
193+
// Upsert the settings from the read-only site settings
194+
for readOnlyItem in readOnlySiteSettings {
195+
if let existingStorageItem = storageSiteSettings?.first(where: { $0.settingID == readOnlyItem.settingID }) {
196+
existingStorageItem.update(with: readOnlyItem)
197+
} else {
198+
let newStorageItem = storage.insertNewObject(ofType: Storage.SiteSetting.self)
199+
newStorageItem.update(with: readOnlyItem)
200+
}
201+
}
202+
203+
// Now, remove any objects that exist in storageSiteSettings but not in readOnlySiteSettings
204+
if let storageSiteSettings {
205+
storageSiteSettings.forEach({ storageItem in
206+
if readOnlySiteSettings.first(where: { $0.settingID == storageItem.settingID } ) == nil {
207+
storage.deleteObject(storageItem)
208+
}
209+
})
210+
}
211+
}
212+
}
213+
214+
// MARK: - Unit Testing Helpers
215+
//
216+
extension SettingStoreMethods {
217+
218+
/// Unit Testing Helper: Updates or Inserts the specified **general** ReadOnly SiteSetting entities in the provided Storage instance.
219+
///
220+
func upsertStoredGeneralSiteSettings(siteID: Int64, readOnlySiteSettings: [Networking.SiteSetting], in storage: StorageType) {
221+
upsertSettings(readOnlySiteSettings, in: storage, siteID: siteID, settingGroup: SiteSettingGroup.general)
222+
}
223+
224+
/// Unit Testing Helper: Updates or Inserts the specified **product** ReadOnly SiteSetting entities in the provided Storage instance.
225+
///
226+
func upsertStoredProductSiteSettings(siteID: Int64, readOnlySiteSettings: [Networking.SiteSetting], in storage: StorageType) {
227+
upsertSettings(readOnlySiteSettings, in: storage, siteID: siteID, settingGroup: SiteSettingGroup.product)
228+
}
229+
}
230+
231+
// MARK: Definitions
232+
extension SettingStoreMethods {
233+
/// Settings keys.
234+
///
235+
private enum SettingKeys {
236+
static let coupons = "woocommerce_enable_coupons"
237+
static let analytics = "woocommerce_analytics_enabled"
238+
static let taxBasedOn = "woocommerce_tax_based_on"
239+
}
240+
241+
private enum SettingValue {
242+
static let yes = "yes"
243+
}
244+
}

0 commit comments

Comments
 (0)