Skip to content

Commit 9d7f634

Browse files
authored
[Woo POS][Historical Orders] Orders Fetching (#16036)
2 parents 722d258 + 7ff28cc commit 9d7f634

27 files changed

+1513
-94
lines changed

Modules/Sources/NetworkingCore/Remote/OrdersRemote.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,30 @@ extension OrdersRemote: POSOrdersRemoteProtocol {
450450
}
451451
}
452452
}
453+
454+
public func loadPOSOrders(siteID: Int64, pageNumber: Int, pageSize: Int) async throws -> PagedItems<Order> {
455+
let parameters: [String: Any] = [
456+
ParameterKeys.page: String(pageNumber),
457+
ParameterKeys.perPage: String(pageSize),
458+
ParameterKeys.statusKey: Defaults.statusAny,
459+
ParameterKeys.usesGMTDates: true,
460+
ParameterKeys.fields: ParameterValues.fieldValues,
461+
ParameterKeys.createdVia: "pos-rest-api"
462+
]
463+
464+
let path = Constants.ordersPath
465+
let request = JetpackRequest(wooApiVersion: .mark3,
466+
method: .get,
467+
siteID: siteID,
468+
path: path,
469+
parameters: parameters,
470+
availableAsRESTRequest: true)
471+
let mapper = OrderListMapper(siteID: siteID)
472+
473+
let orders: [Order] = try await enqueue(request, mapper: mapper)
474+
let hasMorePages = orders.count == pageSize
475+
return PagedItems(items: orders, hasMorePages: hasMorePages, totalItems: nil)
476+
}
453477
}
454478

455479

Modules/Sources/NetworkingCore/Remote/POSOrdersRemoteProtocol.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,8 @@ public protocol POSOrdersRemoteProtocol {
1414
func createPOSOrder(siteID: Int64,
1515
order: Order,
1616
fields: [OrdersRemote.CreateOrderField]) async throws -> Order
17+
18+
func loadPOSOrders(siteID: Int64,
19+
pageNumber: Int,
20+
pageSize: Int) async throws -> PagedItems<Order>
1721
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import Foundation
2+
import struct NetworkingCore.Address
3+
import struct NetworkingCore.OrderItem
4+
import struct NetworkingCore.OrderRefundCondensed
5+
import struct NetworkingCore.MetaData
6+
import enum NetworkingCore.OrderStatusEnum
7+
import struct NetworkingCore.Order
8+
9+
public struct POSOrder: Equatable, Hashable {
10+
public let id: Int64
11+
public let number: String
12+
public let dateCreated: Date
13+
public let status: OrderStatusEnum
14+
public let total: String
15+
public let customerEmail: String?
16+
public let paymentMethodTitle: String
17+
public let lineItems: [POSOrderItem]
18+
public let refunds: [POSOrderRefund]
19+
public let currency: String
20+
public let currencySymbol: String
21+
22+
public init(id: Int64,
23+
number: String,
24+
dateCreated: Date,
25+
status: OrderStatusEnum,
26+
total: String,
27+
customerEmail: String? = nil,
28+
paymentMethodTitle: String,
29+
lineItems: [POSOrderItem] = [],
30+
refunds: [POSOrderRefund] = [],
31+
currency: String,
32+
currencySymbol: String) {
33+
self.id = id
34+
self.number = number
35+
self.dateCreated = dateCreated
36+
self.status = status
37+
self.total = total
38+
self.customerEmail = customerEmail
39+
self.paymentMethodTitle = paymentMethodTitle
40+
self.lineItems = lineItems
41+
self.refunds = refunds
42+
self.currency = currency
43+
self.currencySymbol = currencySymbol
44+
}
45+
}
46+
47+
// MARK: - Conversion from NetworkingCore.Order
48+
public extension POSOrder {
49+
init(from order: NetworkingCore.Order) {
50+
// Extract customer email from billing address
51+
let customerEmail = order.billingAddress?.email
52+
53+
// Convert line items to POS format
54+
let posLineItems = order.items.map { POSOrderItem(from: $0) }
55+
56+
// Convert refunds to POS format
57+
let posRefunds = order.refunds.map { POSOrderRefund(from: $0) }
58+
59+
self.init(
60+
id: order.orderID,
61+
number: order.number,
62+
dateCreated: order.dateCreated,
63+
status: order.status,
64+
total: order.total,
65+
customerEmail: customerEmail,
66+
paymentMethodTitle: order.paymentMethodTitle,
67+
lineItems: posLineItems,
68+
refunds: posRefunds,
69+
currency: order.currency,
70+
currencySymbol: order.currencySymbol
71+
)
72+
}
73+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import Foundation
2+
import struct NetworkingCore.OrderItem
3+
4+
public struct POSOrderItem: Equatable, Hashable {
5+
public let itemID: Int64
6+
public let name: String
7+
public let quantity: Decimal
8+
public let total: String
9+
10+
public init(itemID: Int64,
11+
name: String,
12+
quantity: Decimal,
13+
total: String) {
14+
self.itemID = itemID
15+
self.name = name
16+
self.quantity = quantity
17+
self.total = total
18+
}
19+
}
20+
21+
// MARK: - Conversion from NetworkingCore.OrderItem
22+
public extension POSOrderItem {
23+
init(from orderItem: OrderItem) {
24+
self.init(
25+
itemID: orderItem.itemID,
26+
name: orderItem.name,
27+
quantity: orderItem.quantity,
28+
total: orderItem.total
29+
)
30+
}
31+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import Foundation
2+
import struct NetworkingCore.OrderRefundCondensed
3+
4+
public struct POSOrderRefund: Equatable, Hashable {
5+
public let refundID: Int64
6+
public let total: String
7+
public let reason: String?
8+
9+
public init(refundID: Int64,
10+
total: String,
11+
reason: String? = nil) {
12+
self.refundID = refundID
13+
self.total = total
14+
self.reason = reason
15+
}
16+
}
17+
18+
// MARK: - Conversion from NetworkingCore.OrderRefundCondensed
19+
public extension POSOrderRefund {
20+
init(from refund: OrderRefundCondensed) {
21+
self.init(
22+
refundID: refund.refundID,
23+
total: refund.total,
24+
reason: refund.reason
25+
)
26+
}
27+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import Foundation
2+
import struct NetworkingCore.PagedItems
3+
4+
public protocol PointOfSaleOrderListFetchStrategy {
5+
func fetchOrders(pageNumber: Int) async throws -> PagedItems<POSOrder>
6+
}
7+
8+
struct PointOfSaleDefaultOrderListFetchStrategy: PointOfSaleOrderListFetchStrategy {
9+
private let orderListService: PointOfSaleOrderListServiceProtocol
10+
11+
init(orderListService: PointOfSaleOrderListServiceProtocol) {
12+
self.orderListService = orderListService
13+
}
14+
15+
func fetchOrders(pageNumber: Int) async throws -> PagedItems<POSOrder> {
16+
try await orderListService.providePointOfSaleOrders(pageNumber: pageNumber)
17+
}
18+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import Foundation
2+
import class Networking.AlamofireNetwork
3+
import class Networking.OrdersRemote
4+
5+
public protocol PointOfSaleOrderListFetchStrategyFactoryProtocol {
6+
func defaultStrategy() -> PointOfSaleOrderListFetchStrategy
7+
}
8+
9+
public final class PointOfSaleOrderListFetchStrategyFactory: PointOfSaleOrderListFetchStrategyFactoryProtocol {
10+
private let siteID: Int64
11+
private let ordersRemote: OrdersRemote
12+
13+
public init(siteID: Int64,
14+
credentials: Credentials?) {
15+
self.siteID = siteID
16+
let network = AlamofireNetwork(credentials: credentials)
17+
self.ordersRemote = OrdersRemote(network: network)
18+
}
19+
20+
public func defaultStrategy() -> PointOfSaleOrderListFetchStrategy {
21+
PointOfSaleDefaultOrderListFetchStrategy(orderListService: PointOfSaleOrderListService(siteID: siteID,
22+
ordersRemote: ordersRemote))
23+
}
24+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import Foundation
2+
import enum Alamofire.AFError
3+
import struct NetworkingCore.PagedItems
4+
import struct NetworkingCore.Order
5+
import protocol NetworkingCore.POSOrdersRemoteProtocol
6+
7+
public final class PointOfSaleOrderListService: PointOfSaleOrderListServiceProtocol {
8+
private let ordersRemote: POSOrdersRemoteProtocol
9+
private let siteID: Int64
10+
11+
public init(siteID: Int64, ordersRemote: POSOrdersRemoteProtocol) {
12+
self.siteID = siteID
13+
self.ordersRemote = ordersRemote
14+
}
15+
16+
public func providePointOfSaleOrders(pageNumber: Int = 1) async throws -> PagedItems<POSOrder> {
17+
do {
18+
let pagedOrders = try await ordersRemote.loadPOSOrders(
19+
siteID: siteID,
20+
pageNumber: pageNumber,
21+
pageSize: 25
22+
)
23+
24+
if pageNumber != 1 && pagedOrders.items.count == 0 {
25+
return .init(items: [], hasMorePages: false, totalItems: 0)
26+
}
27+
28+
// Convert Order objects to POSOrder objects
29+
let posOrders = pagedOrders.items.map { POSOrder(from: $0) }
30+
31+
return .init(items: posOrders,
32+
hasMorePages: pagedOrders.hasMorePages,
33+
totalItems: pagedOrders.totalItems)
34+
} catch AFError.explicitlyCancelled {
35+
throw PointOfSaleOrderListServiceError.requestCancelled
36+
} catch {
37+
throw PointOfSaleOrderListServiceError.requestFailed
38+
}
39+
}
40+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import Foundation
2+
import struct NetworkingCore.PagedItems
3+
4+
public enum PointOfSaleOrderListServiceError: Error, Equatable {
5+
case requestFailed
6+
case requestCancelled
7+
}
8+
9+
public protocol PointOfSaleOrderListServiceProtocol {
10+
func providePointOfSaleOrders(pageNumber: Int) async throws -> PagedItems<POSOrder>
11+
}

Modules/Tests/YosemiteTests/Mocks/MockPOSOrdersRemote.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,24 @@ final class MockPOSOrdersRemote: POSOrdersRemoteProtocol {
3333
spyCreatePOSOrderFields = fields
3434
return Order.fake()
3535
}
36+
37+
var mockPagedOrdersResult: Result<PagedItems<Order>, Error> = .success(PagedItems(items: [], hasMorePages: false, totalItems: 0))
38+
var loadPOSOrdersCalled = false
39+
var spySiteID: Int64?
40+
var spyPageNumber: Int?
41+
var spyPageSize: Int?
42+
43+
func loadPOSOrders(siteID: Int64, pageNumber: Int, pageSize: Int) async throws -> PagedItems<Order> {
44+
loadPOSOrdersCalled = true
45+
spySiteID = siteID
46+
spyPageNumber = pageNumber
47+
spyPageSize = pageSize
48+
49+
switch mockPagedOrdersResult {
50+
case .success(let pagedOrders):
51+
return pagedOrders
52+
case .failure(let error):
53+
throw error
54+
}
55+
}
3656
}

0 commit comments

Comments
 (0)