Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions Modules/Sources/NetworkingCore/Remote/OrdersRemote.swift
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,24 @@ public extension OrdersRemote {
case customerID
case currency
}

/// Loads a single order asynchronously for POS
/// - Parameters:
/// - siteID: Site for which we'll fetch the order.
/// - orderID: ID of the order to load.
/// - Returns: The loaded Order.
/// - Throws: Network or parsing errors.
func loadPOSOrder(siteID: Int64, orderID: Int64) async throws -> Order {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: This could be an async wrapper for existing loadOrder, right? So no need to define the function specifically for POS orders

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I first reused the existing method, but it's a bit awkward since it uses non-async version of enqueue that returns an optional Data? and optional Error? which requires to set some unknown` error state to make sure all the code paths are covered. Seemed cleaner to create this new async method.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha, sounds good to me! 🕺

let path = "\(Constants.ordersPath)/\(orderID)"
let request = JetpackRequest(wooApiVersion: .mark3,
method: .get,
siteID: siteID,
path: path,
availableAsRESTRequest: true)
let mapper = OrderMapper(siteID: siteID)

return try await enqueue(request, mapper: mapper)
}
}

private extension OrdersRemote.OrderCreationSource {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public protocol POSOrdersRemoteProtocol {
order: Order,
fields: [OrdersRemote.CreateOrderField]) async throws -> Order

func loadPOSOrder(siteID: Int64, orderID: Int64) async throws -> Order

func loadPOSOrders(siteID: Int64,
pageNumber: Int,
pageSize: Int) async throws -> PagedItems<Order>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ import Codegen
import Foundation
import Networking
import WooFoundation
import enum NetworkingCore.OrderStatusEnum
import struct NetworkingCore.Address
import struct NetworkingCore.MetaData
import struct NetworkingCore.Order
import struct NetworkingCore.OrderItem
import struct NetworkingCore.OrderRefundCondensed


extension Yosemite.JustInTimeMessage {
Expand Down Expand Up @@ -51,6 +57,60 @@ extension Yosemite.JustInTimeMessage {
}
}

extension Yosemite.POSOrder {
public func copy(
id: CopiableProp<Int64> = .copy,
number: CopiableProp<String> = .copy,
dateCreated: CopiableProp<Date> = .copy,
status: CopiableProp<OrderStatusEnum> = .copy,
formattedTotal: CopiableProp<String> = .copy,
formattedSubtotal: CopiableProp<String> = .copy,
customerEmail: NullableCopiableProp<String> = .copy,
paymentMethodID: CopiableProp<String> = .copy,
paymentMethodTitle: CopiableProp<String> = .copy,
lineItems: CopiableProp<[POSOrderItem]> = .copy,
refunds: CopiableProp<[POSOrderRefund]> = .copy,
formattedDiscountTotal: NullableCopiableProp<String> = .copy,
formattedTotalTax: CopiableProp<String> = .copy,
formattedPaymentTotal: CopiableProp<String> = .copy,
formattedNetAmount: NullableCopiableProp<String> = .copy
) -> Yosemite.POSOrder {
let id = id ?? self.id
let number = number ?? self.number
let dateCreated = dateCreated ?? self.dateCreated
let status = status ?? self.status
let formattedTotal = formattedTotal ?? self.formattedTotal
let formattedSubtotal = formattedSubtotal ?? self.formattedSubtotal
let customerEmail = customerEmail ?? self.customerEmail
let paymentMethodID = paymentMethodID ?? self.paymentMethodID
let paymentMethodTitle = paymentMethodTitle ?? self.paymentMethodTitle
let lineItems = lineItems ?? self.lineItems
let refunds = refunds ?? self.refunds
let formattedDiscountTotal = formattedDiscountTotal ?? self.formattedDiscountTotal
let formattedTotalTax = formattedTotalTax ?? self.formattedTotalTax
let formattedPaymentTotal = formattedPaymentTotal ?? self.formattedPaymentTotal
let formattedNetAmount = formattedNetAmount ?? self.formattedNetAmount

return Yosemite.POSOrder(
id: id,
number: number,
dateCreated: dateCreated,
status: status,
formattedTotal: formattedTotal,
formattedSubtotal: formattedSubtotal,
customerEmail: customerEmail,
paymentMethodID: paymentMethodID,
paymentMethodTitle: paymentMethodTitle,
lineItems: lineItems,
refunds: refunds,
formattedDiscountTotal: formattedDiscountTotal,
formattedTotalTax: formattedTotalTax,
formattedPaymentTotal: formattedPaymentTotal,
formattedNetAmount: formattedNetAmount
)
}
}

extension Yosemite.POSSimpleProduct {
public func copy(
id: CopiableProp<UUID> = .copy,
Expand Down
7 changes: 4 additions & 3 deletions Modules/Sources/Yosemite/PointOfSale/OrderList/POSOrder.swift
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import Foundation
import Codegen
import struct NetworkingCore.Address
import struct NetworkingCore.OrderItem
import struct NetworkingCore.OrderRefundCondensed
import struct NetworkingCore.MetaData
import enum NetworkingCore.OrderStatusEnum
import struct NetworkingCore.Order

public struct POSOrder: Equatable, Hashable {
public struct POSOrder: Equatable, Hashable, GeneratedCopiable {
public let id: Int64
public let number: String
public let dateCreated: Date
Expand Down Expand Up @@ -34,8 +35,8 @@ public struct POSOrder: Equatable, Hashable {
paymentMethodTitle: String,
lineItems: [POSOrderItem] = [],
refunds: [POSOrderRefund] = [],
formattedTotalTax: String,
formattedDiscountTotal: String?,
formattedTotalTax: String,
formattedPaymentTotal: String,
formattedNetAmount: String? = nil) {
self.id = id
Expand All @@ -49,8 +50,8 @@ public struct POSOrder: Equatable, Hashable {
self.paymentMethodTitle = paymentMethodTitle
self.lineItems = lineItems
self.refunds = refunds
self.formattedTotalTax = formattedTotalTax
self.formattedDiscountTotal = formattedDiscountTotal
self.formattedTotalTax = formattedTotalTax
self.formattedPaymentTotal = formattedPaymentTotal
self.formattedNetAmount = formattedNetAmount
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ struct POSOrderMapper {
paymentMethodTitle: order.paymentMethodTitle,
lineItems: posLineItems,
refunds: posRefunds,
formattedTotalTax: currencyFormatter.formatAmount(order.totalTax, with: order.currency) ?? "",
formattedDiscountTotal: formattedDiscountTotal,
formattedTotalTax: currencyFormatter.formatAmount(order.totalTax, with: order.currency) ?? "",
formattedPaymentTotal: order.paymentTotal(currencyFormatter: currencyFormatter),
formattedNetAmount: formattedNetAmount
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import struct NetworkingCore.PagedItems

public protocol PointOfSaleOrderListFetchStrategy {
func fetchOrders(pageNumber: Int) async throws -> PagedItems<POSOrder>
func loadOrder(orderID: Int64) async throws -> POSOrder
var supportsCaching: Bool { get }
var showsLoadingWithItems: Bool { get }
var id: String { get }
Expand All @@ -26,6 +27,10 @@ struct PointOfSaleDefaultOrderListFetchStrategy: PointOfSaleOrderListFetchStrate
func fetchOrders(pageNumber: Int) async throws -> PagedItems<POSOrder> {
try await orderListService.providePointOfSaleOrders(pageNumber: pageNumber)
}

func loadOrder(orderID: Int64) async throws -> POSOrder {
try await orderListService.loadOrder(orderID: orderID)
}
}

struct PointOfSaleSearchOrderListFetchStrategy: PointOfSaleOrderListFetchStrategy {
Expand All @@ -43,4 +48,8 @@ struct PointOfSaleSearchOrderListFetchStrategy: PointOfSaleOrderListFetchStrateg
func fetchOrders(pageNumber: Int) async throws -> PagedItems<POSOrder> {
try await orderListService.searchPointOfSaleOrders(searchTerm: searchTerm, pageNumber: pageNumber)
}

func loadOrder(orderID: Int64) async throws -> POSOrder {
try await orderListService.loadOrder(orderID: orderID)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,15 @@ public final class PointOfSaleOrderListService: PointOfSaleOrderListServiceProto
throw PointOfSaleOrderListServiceError.requestFailed
}
}

public func loadOrder(orderID: Int64) async throws -> POSOrder {
do {
let order = try await ordersRemote.loadPOSOrder(siteID: siteID, orderID: orderID)
return mapper.map(order: order)
} catch AFError.explicitlyCancelled {
throw PointOfSaleOrderListServiceError.requestCancelled
} catch {
throw PointOfSaleOrderListServiceError.requestFailed
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ public enum PointOfSaleOrderListServiceError: Error, Equatable {
public protocol PointOfSaleOrderListServiceProtocol {
func providePointOfSaleOrders(pageNumber: Int) async throws -> PagedItems<POSOrder>
func searchPointOfSaleOrders(searchTerm: String, pageNumber: Int) async throws -> PagedItems<POSOrder>
func loadOrder(orderID: Int64) async throws -> POSOrder
}
17 changes: 17 additions & 0 deletions Modules/Tests/YosemiteTests/Mocks/MockPOSOrdersRemote.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,21 @@ final class MockPOSOrdersRemote: POSOrdersRemoteProtocol {
throw error
}
}

var loadPOSOrderCalled = false
var spyLoadPOSOrderID: Int64?
var loadPOSOrderResult: Result<Order, Error> = .success(Order.fake())

func loadPOSOrder(siteID: Int64, orderID: Int64) async throws -> Order {
loadPOSOrderCalled = true
spySiteID = siteID
spyLoadPOSOrderID = orderID

switch loadPOSOrderResult {
case .success(let order):
return order
case .failure(let error):
throw error
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ protocol PointOfSaleOrderListControllerProtocol {
func refreshOrders() async
func loadNextOrders() async
func selectOrder(_ order: POSOrder?)
func updateOrder(orderID: Int64) async throws
}

protocol PointOfSaleSearchingOrderListControllerProtocol: PointOfSaleOrderListControllerProtocol {
Expand Down Expand Up @@ -122,6 +123,11 @@ protocol PointOfSaleSearchingOrderListControllerProtocol: PointOfSaleOrderListCo

ordersViewState = allOrders.isEmpty ? .empty : .loaded(allOrders, hasMoreItems: pagedOrders.hasMorePages)

if let selectedOrderID = selectedOrder?.id,
let updatedSelectedOrder = allOrders.first(where: { $0.id == selectedOrderID }) {
selectedOrder = updatedSelectedOrder
}

if fetchStrategy.supportsCaching {
cachedOrders = allOrders
}
Expand Down Expand Up @@ -169,4 +175,21 @@ protocol PointOfSaleSearchingOrderListControllerProtocol: PointOfSaleOrderListCo
}
}
}

@MainActor
func updateOrder(orderID: Int64) async throws {
let updatedOrder = try await fetchStrategy.loadOrder(orderID: orderID)
let updatedOrders = ordersViewState.orders.map { order in
order.id == orderID ? updatedOrder : order
}

ordersViewState = ordersViewState.updatingOrders(with: updatedOrders)
cachedOrders = cachedOrders.map { order in
order.id == orderID ? updatedOrder : order
}

if selectedOrder?.id == orderID {
selectedOrder = updatedOrder
}
}
}
13 changes: 13 additions & 0 deletions WooCommerce/Classes/POS/Models/POSOrdersViewState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,17 @@ enum POSOrderListState: Equatable {
return []
}
}

func updatingOrders(with updatedOrders: [POSOrder]) -> POSOrderListState {
switch self {
case .loaded(_, let hasMoreItems):
return .loaded(updatedOrders, hasMoreItems: hasMoreItems)
case .loading:
return .loading(updatedOrders)
case .inlineError(_, let error, let context):
return .inlineError(updatedOrders, error: error, context: context)
case .empty, .error:
return self
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ import struct Yosemite.POSOrder

func sendReceipt(order: POSOrder, email: String) async throws {
try await receiptSender.sendReceipt(orderID: order.id, recipientEmail: email)
try await ordersController.updateOrder(orderID: order.id)
}
}
Loading