Skip to content

Commit

Permalink
[Product Global Unique Identifier] Refine Barcode Scanner Search (#14712
Browse files Browse the repository at this point in the history
)
  • Loading branch information
toupper authored Dec 19, 2024
2 parents 9312085 + f8ec465 commit 673a61f
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 36 deletions.
91 changes: 56 additions & 35 deletions Yosemite/Yosemite/Stores/ProductStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -422,11 +422,10 @@ private extension ProductStore {
return onCompletion(.failure(ProductLoadError.emptyIdentifier))
}

searchProductsByIdentifier(siteID: siteID,
keyword: identifier,
completion: { result in
switch result {
case let .success((products, source)):
Task {
do {
let (products, source) = try await searchProductsByIdentifier(for: siteID, keyword: identifier)

let matchedProducts = products.filter { $0.sku == identifier || $0.globalUniqueID == identifier }

guard !matchedProducts.isEmpty else {
Expand All @@ -449,10 +448,10 @@ private extension ProductStore {
onCompletion(.success((.product(product), source)))
})
}
case let .failure(error):
} catch {
onCompletion(.failure(error))
}
})
}
}

/// Adds a product.
Expand Down Expand Up @@ -1279,37 +1278,59 @@ private extension ProductStore {
}

private extension ProductStore {
func searchProductsByIdentifier(siteID: Int64, keyword: String, completion: @escaping (Result<([Product], ItemIdentifierSearchResultSource), Error>) -> Void) {
remote.searchProductsBySKU(for: siteID,
keyword: keyword,
pageNumber: Remote.Default.firstPageNumber,
pageSize: ProductsRemote.Default.pageSize,
completion: { [weak self] result in
var returningResults: [Product] = []
switch result {
case let .success(products):
returningResults = products
case .failure:
break
}
func searchProductsByIdentifier(for siteID: Int64, keyword: String) async throws -> ([Product], ItemIdentifierSearchResultSource) {
async let skuProducts = searchProductsBySKU(for: siteID, keyword: keyword)
async let globalUniqueIdentifierProducts = searchProductsByGlobalUniqueIdentifier(for: siteID, keyword: keyword)

if returningResults.isEmpty {
self?.remote.searchProductsByGlobalUniqueIdentifier(for: siteID,
keyword: keyword,
pageNumber: Remote.Default.firstPageNumber,
pageSize: ProductsRemote.Default.pageSize,
completion: { result in
switch result {
case let .success(products):
completion(.success((products, .globalUniqueIdentifier)))
case .failure(let error):
completion(.failure(error))
}
})
do {
let globalUniqueIdentifierResult = try await globalUniqueIdentifierProducts

if !(try await globalUniqueIdentifierProducts.isEmpty) {
return (globalUniqueIdentifierResult, .globalUniqueIdentifier)
} else {
completion(.success((returningResults, .SKU)))
let skuResult = try await skuProducts

if !(try await skuProducts.isEmpty) {
return (skuResult, .SKU)
} else {
throw ProductLoadError.notFound
}
}
})
} catch {
throw(error)
}
}

func searchProductsBySKU(for siteID: Int64, keyword: String) async throws -> [Product] {
try await withCheckedThrowingContinuation { continuation in
remote.searchProductsBySKU(for: siteID,
keyword: keyword,
pageNumber: Remote.Default.firstPageNumber,
pageSize: ProductsRemote.Default.pageSize) { result in
switch result {
case let .success(products):
continuation.resume(returning: products)
case let .failure(error):
continuation.resume(throwing: error)
}
}
}
}

func searchProductsByGlobalUniqueIdentifier(for siteID: Int64, keyword: String) async throws -> [Product] {
try await withCheckedThrowingContinuation { continuation in
remote.searchProductsByGlobalUniqueIdentifier(for: siteID,
keyword: keyword,
pageNumber: Remote.Default.firstPageNumber,
pageSize: ProductsRemote.Default.pageSize) { result in
switch result {
case let .success(products):
continuation.resume(returning: products)
case let .failure(error):
continuation.resume(throwing: error)
}
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ final class MockProductsRemote {

private var searchProductsBySKUResultsBySKU = [String: Result<[Product], Error>]()

private var searchProductsByGlobalUniqueIdentifierResults = [String: Result<[Product], Error>]()

private var fetchedStockResult: Result<[ProductStock], Error>?
private var fetchedProductReports: Result<[ProductReport], Error>?
private var fetchedVariationReports: Result<[ProductReport], Error>?
Expand Down Expand Up @@ -120,6 +122,13 @@ final class MockProductsRemote {
searchProductsBySKUResultsBySKU[sku] = result
}

/// Set the value passed to the `completion` block if `searchProductsByGlobalUniqueIdentifier()` is called.
///
func whenSearchingProductsByGlobalUniqueIdentifier(identifier: String, thenReturn result: Result<[Product], Error>) {
searchProductsByGlobalUniqueIdentifierResults[identifier] = result
}


func whenFetchingStock(thenReturn result: Result<[ProductStock], Error>) {
fetchedStockResult = result
}
Expand Down Expand Up @@ -265,7 +274,11 @@ extension MockProductsRemote: ProductsRemoteProtocol {
pageNumber: Int,
pageSize: Int,
completion: @escaping (Result<[Product], Error>) -> Void) {
// no-op
if let result = searchProductsByGlobalUniqueIdentifierResults[keyword] {
completion(result)
} else {
XCTFail("\(String(describing: self)) Could not find result for Global Unique Identifier \(keyword)")
}
}

func searchSku(for siteID: Int64, sku: String, completion: @escaping (Result<String, Error>) -> Void) {
Expand Down
2 changes: 2 additions & 0 deletions Yosemite/YosemiteTests/Stores/ProductStoreTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2435,6 +2435,8 @@ final class ProductStoreTests: XCTestCase {
.fake().copy(sku: "chocobars", purchasable: true)
]))

remote.whenSearchingProductsByGlobalUniqueIdentifier(identifier: "chocobars", thenReturn: .success([]))

// When
let result = waitFor { promise in
store.onAction(ProductAction.retrieveFirstPurchasableItemMatchFromIdentifier(siteID: self.sampleSiteID,
Expand Down

0 comments on commit 673a61f

Please sign in to comment.