From 83f0d90a6753da2963f8d3e83016367209b7c8c1 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Thu, 26 Jul 2018 13:39:22 -0300 Subject: [PATCH 01/14] FulfillViewController: Wiring Update Order Action --- .../Orders/FulfillViewController.swift | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/WooCommerce/Classes/ViewRelated/Orders/FulfillViewController.swift b/WooCommerce/Classes/ViewRelated/Orders/FulfillViewController.swift index 19dfec66846..4fcb7573bd3 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/FulfillViewController.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/FulfillViewController.swift @@ -2,6 +2,7 @@ import Foundation import UIKit import Yosemite import Gridicons +import CocoaLumberjack @@ -121,8 +122,42 @@ private extension FulfillViewController { // extension FulfillViewController { + /// Whenever the Fulfillment Action is pressed, we'll mark the order as Completed, and pull back to the previous screen. + /// @IBAction func fulfillWasPressed() { -// TODO: Fill Me! + let done = updateOrderAction(siteID: order.siteID, orderID: order.orderID, status: .completed) + let undo = updateOrderAction(siteID: order.siteID, orderID: order.orderID, status: order.status) + + StoresManager.shared.dispatch(done) + + displayOrderCompleteNotice { + StoresManager.shared.dispatch(undo) + } + + navigationController?.popViewController(animated: true) + } + + /// Returns an Order Update Action that will result in the specified Order Status updated accordingly. + /// + private func updateOrderAction(siteID: Int, orderID: Int, status: OrderStatus) -> Action { + return OrderAction.updateOrder(siteID: siteID, orderID: orderID, status: status, onCompletion: { (_, error) in + guard let error = error.debugDescription else { + return + } + + DDLogError("⛔️ Order Update Failure: [\(orderID).status = \(status.rawValue)]. Error: \(error)") + }) + } + + /// Displays the `Order Fulfilled` Notice. Whenever the `Undo` button gets pressed, we'll execute the `onUndoAction` closure. + /// + private func displayOrderCompleteNotice(onUndoAction: @escaping () -> Void) { + let title = NSLocalizedString("Fulfillment", comment: "Fulfill Notice Title") + let message = NSLocalizedString("Order Marked as Complete!", comment: "Fulfill Notice Message") + let actionTitle = NSLocalizedString("Undo", comment: "Undo Action") + let notice = Notice(title: title, message: message, feedbackType: .success, actionTitle: actionTitle, actionHandler: onUndoAction) + + AppDelegate.shared.noticePresenter.enqueue(notice: notice) } } From 947a9ca21ff978cb0c23897c8a77c42376f4ff93 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Thu, 26 Jul 2018 13:39:32 -0300 Subject: [PATCH 02/14] OrderStore: Fixing invalid parameter --- Yosemite/Yosemite/Stores/OrderStore.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Yosemite/Yosemite/Stores/OrderStore.swift b/Yosemite/Yosemite/Stores/OrderStore.swift index 00e766b0417..8b9e56e805f 100644 --- a/Yosemite/Yosemite/Stores/OrderStore.swift +++ b/Yosemite/Yosemite/Stores/OrderStore.swift @@ -76,7 +76,7 @@ private extension OrderStore { let oldStatus = updateOrderStatus(orderID: orderID, status: status) let remote = OrdersRemote(network: network) - remote.updateOrder(from: siteID, orderID: orderID, status: status.description) { [weak self] (order, error) in + remote.updateOrder(from: siteID, orderID: orderID, status: status.rawValue) { [weak self] (order, error) in guard let order = order else { /// Revert Optimistic Update From aa0860658c6bf8764f59a42314de1a70f477ee27 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Thu, 26 Jul 2018 13:40:05 -0300 Subject: [PATCH 03/14] FulfillViewController: Updating invalid unwrap --- .../Classes/ViewRelated/Orders/FulfillViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/Classes/ViewRelated/Orders/FulfillViewController.swift b/WooCommerce/Classes/ViewRelated/Orders/FulfillViewController.swift index 4fcb7573bd3..d785310a9e5 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/FulfillViewController.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/FulfillViewController.swift @@ -141,7 +141,7 @@ extension FulfillViewController { /// private func updateOrderAction(siteID: Int, orderID: Int, status: OrderStatus) -> Action { return OrderAction.updateOrder(siteID: siteID, orderID: orderID, status: status, onCompletion: { (_, error) in - guard let error = error.debugDescription else { + guard let error = error else { return } From 6acaf2f368308556dbeb88389b9044faac7da269 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Thu, 26 Jul 2018 15:56:02 -0300 Subject: [PATCH 04/14] OrderDetailsViewController: Disabling Row Selection --- .../Orders/OrderDetails/OrderDetailsViewController.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/WooCommerce/Classes/ViewRelated/Orders/OrderDetails/OrderDetailsViewController.swift b/WooCommerce/Classes/ViewRelated/Orders/OrderDetails/OrderDetailsViewController.swift index 1a9dd68196a..77bb2ba44fe 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/OrderDetails/OrderDetailsViewController.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/OrderDetails/OrderDetailsViewController.swift @@ -73,6 +73,7 @@ private extension OrderDetailsViewController { tableView.estimatedRowHeight = Constants.rowHeight tableView.rowHeight = UITableViewAutomaticDimension tableView.refreshControl = refreshControl + tableView.allowsSelection = false } /// Setup: Navigation From 4768c1e081bc94ef77dcbf3c250d48f86782f018 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Thu, 26 Jul 2018 16:23:53 -0300 Subject: [PATCH 05/14] FulfillViewController: Removing Tracking Section --- .../Orders/FulfillViewController.swift | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/WooCommerce/Classes/ViewRelated/Orders/FulfillViewController.swift b/WooCommerce/Classes/ViewRelated/Orders/FulfillViewController.swift index d785310a9e5..23d34198ea2 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/FulfillViewController.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/FulfillViewController.swift @@ -1,8 +1,9 @@ import Foundation import UIKit +import CocoaLumberjack + import Yosemite import Gridicons -import CocoaLumberjack @@ -380,13 +381,14 @@ private extension Section { return Section(title: title, secondaryTitle: nil, rows: [row]) }() - let tracking: Section = { - let title = NSLocalizedString("Optional Tracking Information", comment: "") - let row = Row.trackingAdd - - return Section(title: title, secondaryTitle: nil, rows: [row]) - }() +// TODO: Tracking support to be added via #185 +// let tracking: Section = { +// let title = NSLocalizedString("Optional Tracking Information", comment: "") +// let row = Row.trackingAdd +// +// return Section(title: title, secondaryTitle: nil, rows: [row]) +// }() - return [products, note, address, tracking].compactMap { $0 } + return [products, note, address].compactMap { $0 } } } From 12b8435afca89e306adba4815da09e7a712817d6 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Thu, 26 Jul 2018 16:33:22 -0300 Subject: [PATCH 06/14] OrderStore: Fixing invalid status update --- Yosemite/Yosemite/Stores/OrderStore.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Yosemite/Yosemite/Stores/OrderStore.swift b/Yosemite/Yosemite/Stores/OrderStore.swift index 8b9e56e805f..6291cfe6a91 100644 --- a/Yosemite/Yosemite/Stores/OrderStore.swift +++ b/Yosemite/Yosemite/Stores/OrderStore.swift @@ -108,7 +108,7 @@ extension OrderStore { } let oldStatus = OrderStatus(rawValue: order.status) - order.status = status.description + order.status = status.rawValue storage.saveIfNeeded() return oldStatus From 9c01bb3953deacdcf5b1d3a299cd68d4b1d16af5 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Thu, 26 Jul 2018 16:34:07 -0300 Subject: [PATCH 07/14] OrderDetailsViewController: Wiring ResultsController --- .../OrderDetailsViewController.swift | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/WooCommerce/Classes/ViewRelated/Orders/OrderDetails/OrderDetailsViewController.swift b/WooCommerce/Classes/ViewRelated/Orders/OrderDetails/OrderDetailsViewController.swift index 77bb2ba44fe..e6381a4675a 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/OrderDetails/OrderDetailsViewController.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/OrderDetails/OrderDetailsViewController.swift @@ -3,6 +3,7 @@ import Gridicons import Contacts import MessageUI import Yosemite +import Storage import CocoaLumberjack @@ -38,6 +39,16 @@ class OrderDetailsViewController: UIViewController { } private var sections = [Section]() + /// TODO: Replace with `ResultController` (OR) `ObjectController` ASAP + /// + private lazy var resultsController: ResultsController = { + let viewContext = CoreDataManager.global.viewContext + let predicate = NSPredicate(format: "orderID = %ld", self.viewModel.order.orderID) + let descriptor = NSSortDescriptor(key: "orderID", ascending: true) + + return ResultsController(viewContext: viewContext, matching: predicate, sortedBy: [descriptor]) + }() + // MARK: - View Lifecycle @@ -45,6 +56,7 @@ class OrderDetailsViewController: UIViewController { super.viewDidLoad() configureNavigation() configureTableView() + configureResultsController() registerTableViewCells() registerTableViewHeaderFooters() } @@ -85,6 +97,20 @@ private extension OrderDetailsViewController { navigationItem.backBarButtonItem = UIBarButtonItem(title: String(), style: .plain, target: nil, action: nil) } + /// TODO: Replace with `ResultController` (OR) `ObjectController` ASAP + /// + func configureResultsController() { + try? resultsController.performFetch() + resultsController.onDidChangeContent = { [weak self] in + guard let `self` = self, let order = self.resultsController.fetchedObjects.first else { + return + } + + self.viewModel = OrderDetailsViewModel(order: order) + self.tableView.reloadData() + } + } + /// Setup: Sections /// func reloadSections() { From fd7ee7da6278e40c714346ba611f6cade3e475c6 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Thu, 26 Jul 2018 16:39:11 -0300 Subject: [PATCH 08/14] OrderAction.updateOrder: Updating completion signature --- Yosemite/Yosemite/Actions/OrderAction.swift | 2 +- Yosemite/Yosemite/Stores/OrderStore.swift | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Yosemite/Yosemite/Actions/OrderAction.swift b/Yosemite/Yosemite/Actions/OrderAction.swift index 4d65f73a68b..cad752fc6bb 100644 --- a/Yosemite/Yosemite/Actions/OrderAction.swift +++ b/Yosemite/Yosemite/Actions/OrderAction.swift @@ -8,5 +8,5 @@ import Networking public enum OrderAction: Action { case retrieveOrders(siteID: Int, onCompletion: ([Order]?, Error?) -> Void) case retrieveOrder(siteID: Int, orderID: Int, onCompletion: (Order?, Error?) -> Void) - case updateOrder(siteID: Int, orderID: Int, status: OrderStatus, onCompletion: (Order?, Error?) -> Void) + case updateOrder(siteID: Int, orderID: Int, status: OrderStatus, onCompletion: (Error?) -> Void) } diff --git a/Yosemite/Yosemite/Stores/OrderStore.swift b/Yosemite/Yosemite/Stores/OrderStore.swift index 6291cfe6a91..a81eaf23af7 100644 --- a/Yosemite/Yosemite/Stores/OrderStore.swift +++ b/Yosemite/Yosemite/Stores/OrderStore.swift @@ -71,22 +71,21 @@ private extension OrderStore { /// Updates an Order with the specified Status. /// - func updateOrder(siteID: Int, orderID: Int, status: OrderStatus, onCompletion: @escaping (Order?, Error?) -> Void) { + func updateOrder(siteID: Int, orderID: Int, status: OrderStatus, onCompletion: @escaping (Error?) -> Void) { /// Optimistically update the Status let oldStatus = updateOrderStatus(orderID: orderID, status: status) let remote = OrdersRemote(network: network) remote.updateOrder(from: siteID, orderID: orderID, status: status.rawValue) { [weak self] (order, error) in - guard let order = order else { - - /// Revert Optimistic Update - self?.updateOrderStatus(orderID: orderID, status: oldStatus) - onCompletion(nil, error) + guard let error = error else { + // NOTE: We're *not* actually updating the whole entity here. Reason: Prevent UI inconsistencies!! + onCompletion(nil) return } - self?.upsertStoredOrder(readOnlyOrder: order) - onCompletion(order, nil) + /// Revert Optimistic Update + self?.updateOrderStatus(orderID: orderID, status: oldStatus) + onCompletion(error) } } } From 3c2fe0a6d9c127d8dc20f9ffdf194360bda055d6 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Thu, 26 Jul 2018 16:39:24 -0300 Subject: [PATCH 09/14] FulfillViewController: Wiring updateOrder's callback --- .../Classes/ViewRelated/Orders/FulfillViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/Classes/ViewRelated/Orders/FulfillViewController.swift b/WooCommerce/Classes/ViewRelated/Orders/FulfillViewController.swift index 23d34198ea2..cc94fc98071 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/FulfillViewController.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/FulfillViewController.swift @@ -141,7 +141,7 @@ extension FulfillViewController { /// Returns an Order Update Action that will result in the specified Order Status updated accordingly. /// private func updateOrderAction(siteID: Int, orderID: Int, status: OrderStatus) -> Action { - return OrderAction.updateOrder(siteID: siteID, orderID: orderID, status: status, onCompletion: { (_, error) in + return OrderAction.updateOrder(siteID: siteID, orderID: orderID, status: status, onCompletion: { error in guard let error = error else { return } From 7f030f35a4b2819966359e55b923e0e20c0ece37 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Thu, 26 Jul 2018 17:00:43 -0300 Subject: [PATCH 10/14] OrderStoreTests: Fixing Unit Test --- .../YosemiteTests/Stores/OrderStoreTests.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Yosemite/YosemiteTests/Stores/OrderStoreTests.swift b/Yosemite/YosemiteTests/Stores/OrderStoreTests.swift index 154ec0a8eeb..57f3e9a0753 100644 --- a/Yosemite/YosemiteTests/Stores/OrderStoreTests.swift +++ b/Yosemite/YosemiteTests/Stores/OrderStoreTests.swift @@ -276,10 +276,11 @@ class OrderStoreTests: XCTestCase { // Update: Expected Status is actually coming from `order.json` (Status == .processing actually!) network.simulateResponse(requestUrlSuffix: "orders/963", filename: "order") - let action = OrderAction.updateOrder(siteID: sampleSiteID, orderID: sampleOrderID, status: .processing) { (order, error) in + let action = OrderAction.updateOrder(siteID: sampleSiteID, orderID: sampleOrderID, status: .processing) { error in XCTAssertNil(error) - XCTAssertNotNil(order) - XCTAssert(order!.status == .processing) + + let storageOrder = self.storageManager.viewStorage.loadOrder(orderID: self.sampleOrderID) + XCTAssert(storageOrder?.status == OrderStatus.processing.rawValue) expectation.fulfill() } @@ -299,12 +300,11 @@ class OrderStoreTests: XCTestCase { network.removeAllSimulatedResponses() - let action = OrderAction.updateOrder(siteID: sampleSiteID, orderID: sampleOrderID, status: .processing) { (order, error) in + let action = OrderAction.updateOrder(siteID: sampleSiteID, orderID: sampleOrderID, status: .processing) { error in XCTAssertNotNil(error) - XCTAssertNil(order) - let storedOrder = self.storageManager.viewStorage.loadOrder(orderID: self.sampleOrderID) - XCTAssert(storedOrder?.status == OrderStatus.completed.description) + let storageOrder = self.storageManager.viewStorage.loadOrder(orderID: self.sampleOrderID) + XCTAssert(storageOrder?.status == OrderStatus.completed.rawValue) expectation.fulfill() } From a2c9f0ce1cf7e0b96453e1e2051ab182a5c70f18 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Thu, 26 Jul 2018 18:04:46 -0300 Subject: [PATCH 11/14] ProductDetailsTableViewCell: Updating internal Layout --- .../ProductDetailsTableViewCell.xib | 100 ++++++++++-------- 1 file changed, 55 insertions(+), 45 deletions(-) diff --git a/WooCommerce/Classes/ViewRelated/Orders/OrderDetails/ProductDetailsTableViewCell.xib b/WooCommerce/Classes/ViewRelated/Orders/OrderDetails/ProductDetailsTableViewCell.xib index 962fb9c7adf..18ee3e44ea7 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/OrderDetails/ProductDetailsTableViewCell.xib +++ b/WooCommerce/Classes/ViewRelated/Orders/OrderDetails/ProductDetailsTableViewCell.xib @@ -5,80 +5,90 @@ + + - - + + - + - - + + + + + + + + + - - - - - - - - - + + - - - - - - - - - - - - - + + + + + + @@ -90,7 +100,7 @@ - + From 73455096886de241182c7e13b4c41a65db5f533a Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Thu, 26 Jul 2018 18:06:02 -0300 Subject: [PATCH 12/14] FulfillViewController: Disabling Selection --- .../Classes/ViewRelated/Orders/FulfillViewController.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/WooCommerce/Classes/ViewRelated/Orders/FulfillViewController.swift b/WooCommerce/Classes/ViewRelated/Orders/FulfillViewController.swift index cc94fc98071..31a0b94489f 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/FulfillViewController.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/FulfillViewController.swift @@ -82,6 +82,7 @@ private extension FulfillViewController { /// func setupTableView() { tableView.tableFooterView = actionView + tableView.allowsSelection = false } ///Setup: Action Button! From 65dc259539a9e626f0d64f0cb4a2ea301afbb64b Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Thu, 26 Jul 2018 18:23:53 -0300 Subject: [PATCH 13/14] ProductDetailsTableViewCell: Minor Autolayout Fix --- .../ProductDetailsTableViewCell.xib | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/WooCommerce/Classes/ViewRelated/Orders/OrderDetails/ProductDetailsTableViewCell.xib b/WooCommerce/Classes/ViewRelated/Orders/OrderDetails/ProductDetailsTableViewCell.xib index 18ee3e44ea7..1c78d63261d 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/OrderDetails/ProductDetailsTableViewCell.xib +++ b/WooCommerce/Classes/ViewRelated/Orders/OrderDetails/ProductDetailsTableViewCell.xib @@ -27,20 +27,20 @@ - - + + - +