Skip to content
Merged
7 changes: 7 additions & 0 deletions Modules/Sources/NetworkingCore/Remote/OrdersRemote.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class OrdersRemote: Remote {
/// This method will convert it to UTC ISO 8601 before calling the REST API.
/// - customerID: If given, limit response to orders placed by a customer.
/// - productID: If given, limit response to orders including the given product.
/// - createdVia: If given, limit response to orders created via the specified source (e.g. "pos-rest-api" for Point of Sale).
/// - pageNumber: Number of page that should be retrieved.
/// - pageSize: Number of Orders to be retrieved per page.
/// - completion: Closure to be executed upon completion.
Expand All @@ -33,6 +34,7 @@ public class OrdersRemote: Remote {
modifiedAfter: Date? = nil,
customerID: Int64? = nil,
productID: Int64? = nil,
createdVia: String? = nil,
pageNumber: Int = Defaults.pageNumber,
pageSize: Int = Defaults.pageSize,
completion: @escaping (Result<[Order], Error>) -> Void) {
Expand Down Expand Up @@ -66,6 +68,10 @@ public class OrdersRemote: Remote {
parameters[ParameterKeys.product] = productID
}

if let createdVia {
parameters[ParameterKeys.createdVia] = createdVia
}

return parameters
}()

Expand Down Expand Up @@ -470,6 +476,7 @@ public extension OrdersRemote {
static let usesGMTDates: String = "dates_are_gmt"
static let customer = "customer"
static let product = "product"
static let createdVia = "created_via"
}

enum ParameterValues {
Expand Down
4 changes: 4 additions & 0 deletions Modules/Sources/Yosemite/Actions/OrderAction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public enum OrderAction: Action {
/// doesn't matter. It will be converted to UTC later.
/// - customerID: Only include orders placed by the given customer.
/// - productID: Only include orders with `lineItems` including the given product.
/// - createdVia: Only include orders created via the specified source (e.g. "pos-rest-api" for Point of Sale).
///
case fetchFilteredOrders(
siteID: Int64,
Expand All @@ -42,6 +43,7 @@ public enum OrderAction: Action {
modifiedAfter: Date? = nil,
customerID: Int64? = nil,
productID: Int64? = nil,
createdVia: String? = nil,
writeStrategy: OrdersStorageWriteStrategy,
pageSize: Int,
onCompletion: (TimeInterval, Result<[Order], Error>) -> Void
Expand All @@ -58,6 +60,7 @@ public enum OrderAction: Action {
/// doesn't matter. It will be converted to UTC later.
/// - customerID: Only include orders placed by the given customer.
/// - productID: Only include orders with `lineItems` including the given product.
/// - createdVia: Only include orders created via the specified source (e.g. "pos-rest-api" for Point of Sale).
///
case synchronizeOrders(siteID: Int64,
statuses: [String]?,
Expand All @@ -66,6 +69,7 @@ public enum OrderAction: Action {
modifiedAfter: Date? = nil,
customerID: Int64? = nil,
productID: Int64? = nil,
createdVia: String? = nil,
pageNumber: Int,
pageSize: Int,
onCompletion: (TimeInterval, Error?) -> Void)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ struct MockOrderActionHandler: MockActionHandler {

func handle(action: ActionType) {
switch action {
case .fetchFilteredOrders(let siteID, _, _, _, _, _, _, let writeStrategy, let pageSize, let onCompletion):
case .fetchFilteredOrders(let siteID, _, _, _, _, _, _, _, let writeStrategy, let pageSize, let onCompletion):
fetchFilteredAndAllOrders(siteID: siteID,
writeStrategy: writeStrategy,
pageSize: pageSize,
Expand All @@ -25,7 +25,7 @@ struct MockOrderActionHandler: MockActionHandler {
} else {
onCompletion(.failure(NSError(domain: "", code: 0)))
}
case .updateOrderStatus(let siteID, let orderID, let status, let onCompletion):
case .updateOrderStatus(_, _, _, let onCompletion):
onCompletion(nil)

default: unimplementedAction(action: action)
Expand Down
12 changes: 8 additions & 4 deletions Modules/Sources/Yosemite/Stores/OrderStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,31 +37,32 @@ public class OrderStore: Store {
retrieveOrderRemotely(siteID: siteID, orderID: orderID, onCompletion: onCompletion)
case .searchOrders(let siteID, let keyword, let pageNumber, let pageSize, let onCompletion):
searchOrders(siteID: siteID, keyword: keyword, pageNumber: pageNumber, pageSize: pageSize, onCompletion: onCompletion)
case let .fetchFilteredOrders(siteID, statuses, after, before, modifiedAfter, customerID, productID, writeStrategy, pageSize, onCompletion):
case let .fetchFilteredOrders(siteID, statuses, after, before, modifiedAfter, customerID, productID, createdVia, writeStrategy, pageSize, onCompletion):
fetchFilteredOrders(siteID: siteID,
statuses: statuses,
after: after,
before: before,
modifiedAfter: modifiedAfter,
customerID: customerID,
productID: productID,
createdVia: createdVia,
writeStrategy: writeStrategy,
pageSize: pageSize,
onCompletion: onCompletion)
case let .synchronizeOrders(siteID, statuses, after, before, modifiedAfter, customerID, productID, pageNumber, pageSize, onCompletion):
case let .synchronizeOrders(siteID, statuses, after, before, modifiedAfter, customerID, productID, createdVia, pageNumber, pageSize, onCompletion):
synchronizeOrders(siteID: siteID,
statuses: statuses,
after: after,
before: before,
modifiedAfter: modifiedAfter,
customerID: customerID,
productID: productID,
createdVia: createdVia,
pageNumber: pageNumber,
pageSize: pageSize,
onCompletion: onCompletion)
case .updateOrderStatus(let siteID, let orderID, let statusKey, let onCompletion):
updateOrder(siteID: siteID, orderID: orderID, status: statusKey, onCompletion: onCompletion)

case let .updateOrder(siteID, order, giftCard, fields, onCompletion):
updateOrder(siteID: siteID, order: order, giftCard: giftCard, fields: fields, onCompletion: onCompletion)
case let .updateOrderOptimistically(siteID, order, fields, onCompletion):
Expand All @@ -70,7 +71,6 @@ public class OrderStore: Store {
createSimplePaymentsOrder(siteID: siteID, status: status, amount: amount, taxable: taxable, onCompletion: onCompletion)
case let .createOrder(siteID, order, giftCard, onCompletion):
createOrder(siteID: siteID, order: order, giftCard: giftCard, onCompletion: onCompletion)

case let .updateSimplePaymentsOrder(siteID, orderID, feeID, status, amount, amountName, taxable, orderNote, email, onCompletion):
updateSimplePaymentsOrder(siteID: siteID,
orderID: orderID,
Expand Down Expand Up @@ -148,6 +148,7 @@ private extension OrderStore {
modifiedAfter: Date?,
customerID: Int64?,
productID: Int64?,
createdVia: String?,
writeStrategy: OrderAction.OrdersStorageWriteStrategy,
pageSize: Int,
onCompletion: @escaping (TimeInterval, Result<[Order], Error>) -> Void) {
Expand All @@ -161,6 +162,7 @@ private extension OrderStore {
modifiedAfter: modifiedAfter,
customerID: customerID,
productID: productID,
createdVia: createdVia,
pageNumber: pageNumber,
pageSize: pageSize) { [weak self] result in
switch result {
Expand Down Expand Up @@ -189,6 +191,7 @@ private extension OrderStore {
modifiedAfter: Date?,
customerID: Int64?,
productID: Int64?,
createdVia: String?,
pageNumber: Int,
pageSize: Int,
onCompletion: @escaping (TimeInterval, Error?) -> Void) {
Expand All @@ -200,6 +203,7 @@ private extension OrderStore {
modifiedAfter: modifiedAfter,
customerID: customerID,
productID: productID,
createdVia: createdVia,
pageNumber: pageNumber,
pageSize: pageSize) { [weak self] result in
switch result {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,6 @@ enum FilterListValueSelectorConfig {
case products(siteID: Int64)
// Filter list selector for customer
case customer(siteID: Int64)
// Filter list selector for sales channel
case salesChannel

}

Expand Down Expand Up @@ -299,10 +297,6 @@ private extension FilterListViewController {
self.listSelector.reloadData()
}
self.listSelector.navigationController?.pushViewController(statusesFilterVC, animated: true)
case .salesChannel:
// TODO: Make OrderSalesChannelFilterViewController, and handle filtering selection WOOMOB-711
let emptyViewController = EmptyStateViewController(style: .list)
self.listSelector.navigationController?.pushViewController(emptyViewController, animated: true)
case .ordersDateRange:
let selectedOrderFilter = selected.selectedValue as? OrderDateRangeFilter
let datesFilterVC = OrderDatesFilterViewController(selected: selectedOrderFilter) { dateRangeFilter in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ final class FilterOrderListViewModel: FilterListViewModel {
dateRangeFilterViewModel.selectedValue = filter.dateRange
productFilterViewModel.selectedValue = filter.product
customerFilterViewModel.selectedValue = filter.customer
salesChannelFilterViewModel.selectedValue = filter.salesChannel
analytics.track(event: .FilterHistory.trackPastFilterApplied(source: source))
}

Expand Down Expand Up @@ -210,6 +211,9 @@ final class FilterOrderListViewModel: FilterListViewModel {

let clearedCustomer: CustomerFilter? = nil
customerFilterViewModel.selectedValue = clearedCustomer

let clearSalesChannel: SalesChannelFilter? = nil
salesChannelFilterViewModel.selectedValue = clearSalesChannel
}
}

Expand Down Expand Up @@ -262,8 +266,9 @@ extension FilterOrderListViewModel.OrderListFilter {
listSelectorConfig: .customer(siteID: siteID),
selectedValue: filters.customer)
case .salesChannel:
let salesChannelOptions: [FilterOrderListViewModel.SalesChannelFilter] = [.any, .pointOfSale]
return FilterTypeViewModel(title: title,
listSelectorConfig: .salesChannel,
listSelectorConfig: .staticOptions(options: salesChannelOptions),
selectedValue: filters.salesChannel)
}
}
Expand Down Expand Up @@ -375,16 +380,30 @@ extension CustomerFilter: FilterType {
extension FilterOrderListViewModel {
enum SalesChannelFilter: FilterType {
case pointOfSale
case any

var description: String {
switch self {
case .pointOfSale:
return "POS"
return NSLocalizedString(
"salesChannelFilter.row.pos.description",
value: "Point of Sale",
comment: "Description for the Sales channel filter option, when selecting 'Point of Sale' orders")
case .any:
return NSLocalizedString(
"salesChannelFilter.row.any.description",
value: "Any",
comment: "Description for the Sales channel filter option, when selecting 'Any' order")
}
}

var isActive: Bool {
return true
switch self {
case .pointOfSale:
return true
case .any:
return false
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ struct OrderListSyncActionUseCase {
let endDate = filters?.dateRange?.computedEndDate
let productID = filters?.product?.id
let customerID = filters?.customer?.id
let createdVia = filters?.salesChannel == .pointOfSale ? "pos-rest-api" : nil

if pageNumber == Defaults.pageFirstIndex {
let deleteAllBeforeSaving = reason == SyncReason.pullToRefresh || reason == SyncReason.newFiltersApplied
Expand All @@ -76,6 +77,7 @@ struct OrderListSyncActionUseCase {
modifiedAfter: modifiedAfter,
customerID: customerID,
productID: productID,
createdVia: createdVia,
writeStrategy: deleteAllBeforeSaving ? .deleteAllBeforeSaving : .save,
pageSize: pageSize,
onCompletion: { timeInterval, result in
Expand All @@ -96,6 +98,7 @@ struct OrderListSyncActionUseCase {
before: endDate,
customerID: customerID,
productID: productID,
createdVia: createdVia,
pageNumber: pageNumber,
pageSize: pageSize,
onCompletion: completionHandler
Expand Down
17 changes: 16 additions & 1 deletion WooCommerce/Classes/ViewRelated/Orders/OrderListViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,23 @@ final class OrderListViewModel {
return NSCompoundPredicate(andPredicateWithSubpredicates: predicates)
}()

let predicateSalesChannel: NSPredicate? = {
guard let salesChannelFilter = filters?.salesChannel else {
return nil
}

switch salesChannelFilter {
case .pointOfSale:
let predicate = NSPredicate(format: "createdVia == %@", "pos-rest-api")
return predicate
case .any:
return nil
Comment on lines +259 to +263
Copy link
Contributor

Choose a reason for hiding this comment

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

Using it, I immediately felt that there should be a web option.

Other options I've seen in the backend are checkout and rest-api – presumably there are more. checkout came from both the block and classic checkouts, but I did see store_api for a draft order – it got changed to checkout when the order was paid for though.

I don't know how much you've discussed it... even though the fix is out of scope of this PR, it feels wrong from a user perspective right now. Selecting "not POS" would be fine but isn't possible right now, as far as I can see.

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 don't think it was discussed at the time, but agree: Currently wp-admin already shows a sales channel filter within orders for All Sales Channels, Admin, Checkout, and Point of Sale. So we should do the same in-app

Screenshot 2025-07-14 at 12 17 59

}
}()

let siteIDPredicate = NSPredicate(format: "siteID = %lld", siteID)
let queryPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [siteIDPredicate, predicateStatus, predicateDateRanges])
let allPredicates = [siteIDPredicate, predicateStatus, predicateDateRanges, predicateSalesChannel].compactMap { $0 }
let queryPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: allPredicates)

return FetchResultSnapshotsProvider<StorageOrder>.Query(
sortDescriptor: NSSortDescriptor(keyPath: \StorageOrder.dateCreated, ascending: false),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,6 @@ final class OrdersRootViewController: UIViewController {
let viewModel = FilterOrderListViewModel(filters: filters, allowedStatuses: allowedStatuses, siteID: siteID)
let filterOrderListViewController = FilterListViewController(viewModel: viewModel, onFilterAction: { [weak self] filters in
self?.filters = filters

self?.analytics.track(event: .OrdersFilter.onFilterOrders(filters: filters))
}, onClearAction: {
}, onDismissAction: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ private extension PushNotificationBackgroundSynchronizerTests {
// Mock sync order list
stores.whenReceivingAction(ofType: OrderAction.self) { action in
switch action {
case let .fetchFilteredOrders(_, _, _, _, _, _, _, _, _, onCompletion):
case let .fetchFilteredOrders(_, _, _, _, _, _, _, _, _, _, onCompletion):
self.storage.insertSampleOrder(readOnlyOrder: order)
onCompletion(0, .success([order]))
default:
Expand All @@ -112,7 +112,7 @@ private extension PushNotificationBackgroundSynchronizerTests {
// Mock sync order list & single order
stores.whenReceivingAction(ofType: OrderAction.self) { action in
switch action {
case let .fetchFilteredOrders(_, _, _, _, _, _, _, _, _, onCompletion):
case let .fetchFilteredOrders(_, _, _, _, _, _, _, _, _, _, onCompletion):
onCompletion(0, .success([]))
case let .retrieveOrderRemotely(_, _, onCompletion):
self.storage.insertSampleOrder(readOnlyOrder: order)
Expand All @@ -129,7 +129,7 @@ private extension PushNotificationBackgroundSynchronizerTests {
// Mock sync order list & single order
stores.whenReceivingAction(ofType: OrderAction.self) { action in
switch action {
case let .fetchFilteredOrders(_, _, _, _, _, _, _, _, _, onCompletion):
case let .fetchFilteredOrders(_, _, _, _, _, _, _, _, _, _, onCompletion):
onCompletion(0, .success([]))
case let .retrieveOrderRemotely(_, _, onCompletion):
self.storage.insertSampleOrder(readOnlyOrder: Self.sampleOrderWithNoteFullDataOrderID)
Expand Down
Loading
Loading