Skip to content

Commit 10aa71c

Browse files
committed
Added final coupon and item storage support
1 parent bb4bb36 commit 10aa71c

File tree

5 files changed

+84
-12
lines changed

5 files changed

+84
-12
lines changed

Storage/Storage/Model/Order+CoreDataProperties.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ extension Order {
4747
@NSManaged public var shippingPhone: String?
4848
@NSManaged public var shippingEmail: String?
4949
@NSManaged public var shippingState: String?
50-
@NSManaged public var coupons: NSSet?
51-
@NSManaged public var items: NSSet?
50+
@NSManaged public var coupons: Set<OrderCoupon>?
51+
@NSManaged public var items: Set<OrderItem>?
5252
}
5353

5454
// MARK: Generated accessors for coupons

Storage/Storage/Tools/StorageType+Extensions.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,18 @@ public extension StorageType {
2525
let predicate = NSPredicate(format: "orderID = %ld", orderID)
2626
return firstObject(ofType: Order.self, matching: predicate)
2727
}
28+
29+
/// Retrieves the Stored Order Item.
30+
///
31+
public func loadOrderItem(itemID: Int) -> OrderItem? {
32+
let predicate = NSPredicate(format: "itemID = %ld", itemID)
33+
return firstObject(ofType: OrderItem.self, matching: predicate)
34+
}
35+
36+
/// Retrieves the Stored Order Coupon.
37+
///
38+
public func loadCouponItem(couponID: Int) -> OrderCoupon? {
39+
let predicate = NSPredicate(format: "couponID = %ld", couponID)
40+
return firstObject(ofType: OrderCoupon.self, matching: predicate)
41+
}
2842
}

Yosemite/Yosemite/Model/Order+ReadOnlyConvertible.swift

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,14 @@ extension Storage.Order: ReadOnlyConvertible {
5252
shippingCountry = order.shippingAddress.country
5353
shippingPhone = order.shippingAddress.phone
5454
shippingEmail = order.shippingAddress.email
55-
56-
// TODO: items, coupons
5755
}
5856

5957
/// Returns a ReadOnly version of the receiver.
6058
///
6159
public func toReadOnly() -> Yosemite.Order {
60+
let orderItems = items?.map { $0.toReadOnly() } ?? [Yosemite.OrderItem]()
61+
let orderCoupons = coupons?.map { $0.toReadOnly() } ?? [Yosemite.OrderCouponLine]()
62+
6263
return Order(orderID: Int(orderID),
6364
parentID: Int(parentID),
6465
customerID: Int(customerID),
@@ -76,12 +77,10 @@ extension Storage.Order: ReadOnlyConvertible {
7677
total: total ?? "",
7778
totalTax: totalTax ?? "",
7879
paymentMethodTitle: paymentMethodTitle ?? "",
79-
items: [],
80+
items: orderItems,
8081
billingAddress: createReadOnlyBillingAddress(),
8182
shippingAddress: createReadOnlyShippingAddress(),
82-
coupons: [])
83-
84-
// TODO: ^^^^ items, coupons ^^^^
83+
coupons: orderCoupons)
8584
}
8685

8786

Yosemite/Yosemite/Stores/OrderStore.swift

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ private extension OrderStore {
7171

7272
// MARK: - Persistance
7373
//
74-
extension OrderStore {
74+
private extension OrderStore {
7575

7676
/// Updates (OR Inserts) the specified ReadOnly Order Entity into the Storage Layer.
7777
///
@@ -81,6 +81,8 @@ extension OrderStore {
8181
let storage = storageManager.viewStorage
8282
let storageOrder = storage.loadOrder(orderID: readOnlyOrder.orderID) ?? storage.insertNewObject(ofType: Storage.Order.self)
8383

84+
// TODO: items & coupons
85+
8486
storageOrder.update(with: readOnlyOrder)
8587
storage.saveIfNeeded()
8688
}
@@ -91,12 +93,69 @@ extension OrderStore {
9193
assert(Thread.isMainThread)
9294

9395
let storage = storageManager.viewStorage
94-
9596
for readOnlyOrder in readOnlyOrders {
9697
let storageOrder = storage.loadOrder(orderID: readOnlyOrder.orderID) ?? storage.insertNewObject(ofType: Storage.Order.self)
9798
storageOrder.update(with: readOnlyOrder)
99+
handleOrderItems(readOnlyOrder, storageOrder, storage)
100+
handleOrderCoupons(readOnlyOrder, storageOrder, storage)
98101
}
99102

100103
storage.saveIfNeeded()
101104
}
105+
106+
/// Updates, inserts, and prunes the provided StorageOrder's items using the provided read-only Order's items
107+
///
108+
func handleOrderItems(_ readOnlyOrder: Networking.Order, _ storageOrder: Storage.Order, _ storage: StorageType) {
109+
guard !readOnlyOrder.items.isEmpty else {
110+
// No items in the read-only order, so remove all the items in Storage.Order
111+
storageOrder.items?.forEach { storageOrder.removeFromItems($0) }
112+
return
113+
}
114+
115+
// Upsert the items from the read-only order
116+
for readOnlyItem in readOnlyOrder.items {
117+
if let existingStorageItem = storage.loadOrderItem(itemID: readOnlyItem.itemID) {
118+
existingStorageItem.update(with: readOnlyItem)
119+
} else {
120+
let newStorageItem = storage.insertNewObject(ofType: Storage.OrderItem.self)
121+
newStorageItem.update(with: readOnlyItem)
122+
storageOrder.addToItems(newStorageItem)
123+
}
124+
}
125+
126+
// Now, remove any objects that exist in storageOrder.items but not in readOnlyOrder.items
127+
storageOrder.items?.forEach({ storageItem in
128+
if readOnlyOrder.items.first(where: { $0.itemID == storageItem.itemID } ) == nil {
129+
storageOrder.removeFromItems(storageItem)
130+
}
131+
})
132+
}
133+
134+
/// Updates, inserts, and prunes the provided StorageOrder's coupons using the provided read-only Order's coupons
135+
///
136+
func handleOrderCoupons(_ readOnlyOrder: Networking.Order, _ storageOrder: Storage.Order, _ storage: StorageType) {
137+
guard !readOnlyOrder.coupons.isEmpty else {
138+
// No coupons in the read-only order, so remove all the coupons in Storage.Order
139+
storageOrder.coupons?.forEach { storageOrder.removeFromCoupons($0) }
140+
return
141+
}
142+
143+
// Upsert the coupons from the read-only order
144+
for readOnlyCoupon in readOnlyOrder.coupons {
145+
if let existingStorageCoupon = storage.loadCouponItem(couponID: readOnlyCoupon.couponID) {
146+
existingStorageCoupon.update(with: readOnlyCoupon)
147+
} else {
148+
let newStorageCoupon = storage.insertNewObject(ofType: Storage.OrderCoupon.self)
149+
newStorageCoupon.update(with: readOnlyCoupon)
150+
storageOrder.addToCoupons(newStorageCoupon)
151+
}
152+
}
153+
154+
// Now, remove any objects that exist in storageOrder.coupons but not in readOnlyOrder.coupons
155+
storageOrder.coupons?.forEach({ storageCoupon in
156+
if readOnlyOrder.coupons.first(where: { $0.couponID == storageCoupon.couponID } ) == nil {
157+
storageOrder.removeFromCoupons(storageCoupon)
158+
}
159+
})
160+
}
102161
}

Yosemite/YosemiteTests/Stores/OrderStoreTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ class OrderStoreTests: XCTestCase {
7878
wait(for: [expectation], timeout: Constants.expectationTimeout)
7979
}
8080

81-
/// Verifies that `OrderAction.retrieveOrders` effectively persists all of the order fields correctly.
81+
/// Verifies that `OrderAction.retrieveOrders` effectively persists all of the order fields correctly across all of the related Order objects (items, coupons, etc).
8282
///
8383
func testRetrieveOrdersEffectivelyPersistsOrderFields() {
8484
let expectation = self.expectation(description: "Persist order list")
@@ -95,7 +95,7 @@ class OrderStoreTests: XCTestCase {
9595
let readOnlyStoredOrder = storedOrder?.toReadOnly()
9696
XCTAssertNotNil(storedOrder)
9797
XCTAssertNotNil(readOnlyStoredOrder)
98-
//XCTAssertEqual(readOnlyStoredOrder, remoteOrder)
98+
XCTAssertEqual(readOnlyStoredOrder, remoteOrder)
9999

100100
expectation.fulfill()
101101
}

0 commit comments

Comments
 (0)