Skip to content

Commit 8c7ebbf

Browse files
authored
Merge pull request #7463 from woocommerce/issue/fix-adding-products-bug
Urgent: Fix adding products on orders
2 parents 33e524e + 6388cdf commit 8c7ebbf

File tree

4 files changed

+52
-14
lines changed

4 files changed

+52
-14
lines changed

WooCommerce/Classes/ViewRelated/Orders/Order Creation/EditableOrderViewModel.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,9 @@ final class EditableOrderViewModel: ObservableObject {
171171
ProductSelectorViewModel(siteID: siteID, purchasableItemsOnly: true, storageManager: storageManager, stores: stores) { [weak self] product in
172172
guard let self = self else { return }
173173
self.addProductToOrder(product)
174-
} onVariationSelected: { [weak self] variation in
174+
} onVariationSelected: { [weak self] variation, parentProduct in
175175
guard let self = self else { return }
176-
self.addProductVariationToOrder(variation)
176+
self.addProductVariationToOrder(variation, parent: parentProduct)
177177
}
178178
}()
179179

@@ -654,6 +654,7 @@ private extension EditableOrderViewModel {
654654
/// Adds a selected product (from the product list) to the order.
655655
///
656656
func addProductToOrder(_ product: Product) {
657+
// Needed because `allProducts` is only updated at start, so product from new pages are not synced.
657658
if !allProducts.contains(product) {
658659
allProducts.append(product)
659660
}
@@ -666,7 +667,12 @@ private extension EditableOrderViewModel {
666667

667668
/// Adds a selected product variation (from the product list) to the order.
668669
///
669-
func addProductVariationToOrder(_ variation: ProductVariation) {
670+
func addProductVariationToOrder(_ variation: ProductVariation, parent product: Product) {
671+
// Needed because `allProducts` is only updated at start, so product from new pages are not synced.
672+
if !allProducts.contains(product) {
673+
allProducts.append(product)
674+
}
675+
670676
if !allProductVariations.contains(variation) {
671677
allProductVariations.append(variation)
672678
}

WooCommerce/Classes/ViewRelated/Products/ProductSelector/ProductSelectorViewModel.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ final class ProductSelectorViewModel: ObservableObject {
7171

7272
/// Closure to be invoked when a product variation is selected
7373
///
74-
private let onVariationSelected: ((ProductVariation) -> Void)?
74+
private let onVariationSelected: ((ProductVariation, Product) -> Void)?
7575

7676
/// Closure to be invoked when multiple selection is completed
7777
///
@@ -146,7 +146,7 @@ final class ProductSelectorViewModel: ObservableObject {
146146
storageManager: StorageManagerType = ServiceLocator.storageManager,
147147
stores: StoresManager = ServiceLocator.stores,
148148
onProductSelected: ((Product) -> Void)? = nil,
149-
onVariationSelected: ((ProductVariation) -> Void)? = nil) {
149+
onVariationSelected: ((ProductVariation, Product) -> Void)? = nil) {
150150
self.siteID = siteID
151151
self.storageManager = storageManager
152152
self.stores = stores

WooCommerce/Classes/ViewRelated/Products/ProductSelector/ProductVariationSelectorViewModel.swift

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ final class ProductVariationSelectorViewModel: ObservableObject {
5151

5252
/// Closure to be invoked when a product variation is selected
5353
///
54-
let onVariationSelected: ((ProductVariation) -> Void)?
54+
let onVariationSelected: ((ProductVariation, Product) -> Void)?
5555

5656
/// All selected product variations if the selector supports multiple selections.
5757
///
@@ -79,6 +79,15 @@ final class ProductVariationSelectorViewModel: ObservableObject {
7979
}
8080
}
8181

82+
/// Product Result Controller.
83+
/// Used the retrieve the parent product upon selecting a variation.
84+
///
85+
private lazy var productResultsController: ResultsController<StorageProduct> = {
86+
let predicate = NSPredicate(format: "siteID == %lld AND productID == %lld", siteID, productID)
87+
let resultsController = ResultsController<StorageProduct>(storageManager: storageManager, matching: predicate, sortedBy: [])
88+
return resultsController
89+
}()
90+
8291
/// Product Variations Results Controller.
8392
///
8493
private lazy var productVariationsResultsController: ResultsController<StorageProductVariation> = {
@@ -103,7 +112,7 @@ final class ProductVariationSelectorViewModel: ObservableObject {
103112
purchasableItemsOnly: Bool = false,
104113
storageManager: StorageManagerType = ServiceLocator.storageManager,
105114
stores: StoresManager = ServiceLocator.stores,
106-
onVariationSelected: ((ProductVariation) -> Void)? = nil) {
115+
onVariationSelected: ((ProductVariation, Product) -> Void)? = nil) {
107116
self.siteID = siteID
108117
self.productID = productID
109118
self.productName = productName
@@ -125,7 +134,7 @@ final class ProductVariationSelectorViewModel: ObservableObject {
125134
purchasableItemsOnly: Bool = false,
126135
storageManager: StorageManagerType = ServiceLocator.storageManager,
127136
stores: StoresManager = ServiceLocator.stores,
128-
onVariationSelected: ((ProductVariation) -> Void)? = nil) {
137+
onVariationSelected: ((ProductVariation, Product) -> Void)? = nil) {
129138
self.init(siteID: siteID,
130139
productID: product.productID,
131140
productName: product.name,
@@ -140,11 +149,18 @@ final class ProductVariationSelectorViewModel: ObservableObject {
140149
/// Select a product variation to add to the order
141150
///
142151
func selectVariation(_ variationID: Int64) {
143-
guard let selectedVariation = productVariations.first(where: { $0.productVariationID == variationID }) else {
152+
153+
// Fetch parent product
154+
// Needed because the parent product contains the product name & attributes.
155+
try? productResultsController.performFetch()
156+
157+
guard let parentProduct = productResultsController.fetchedObjects.first,
158+
let selectedVariation = productVariations.first(where: { $0.productVariationID == variationID }) else {
144159
return
145160
}
161+
146162
if let onVariationSelected = onVariationSelected {
147-
onVariationSelected(selectedVariation)
163+
onVariationSelected(selectedVariation, parentProduct)
148164
} else {
149165
toggleSelection(productVariationID: variationID)
150166
}

WooCommerce/WooCommerceTests/ViewRelated/Orders/Order Creation/ProductVariationSelectorViewModelTests.swift

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -208,26 +208,35 @@ final class ProductVariationSelectorViewModelTests: XCTestCase {
208208
func test_selectVariation_invokes_onVariationSelected_closure_for_existing_variation() {
209209
// Given
210210
var selectedVariationID: Int64?
211-
let product = Product.fake().copy(productID: sampleProductID)
211+
var selectedProductID: Int64?
212+
213+
let product = Product.fake().copy(siteID: sampleSiteID, productID: sampleProductID)
212214
let productVariation = sampleProductVariation.copy(productVariationID: 1)
213215
insert(productVariation)
216+
insert(product)
217+
214218
let viewModel = ProductVariationSelectorViewModel(siteID: sampleSiteID,
215219
product: product,
216220
storageManager: storageManager,
217-
onVariationSelected: { selectedVariationID = $0.productVariationID })
221+
onVariationSelected: { variation, product in
222+
selectedVariationID = variation.productVariationID
223+
selectedProductID = product.productID
224+
})
218225

219226
// When
220227
viewModel.selectVariation(productVariation.productVariationID)
221228

222229
// Then
223230
XCTAssertEqual(selectedVariationID, productVariation.productVariationID)
231+
XCTAssertEqual(selectedProductID, product.productID)
224232
}
225233

226234
func test_selecting_a_variation_set_its_row_to_selected() {
227235
// Given
228-
let product = Product.fake().copy(productID: sampleProductID)
236+
let product = Product.fake().copy(siteID: sampleSiteID, productID: sampleProductID)
229237
let productVariation = sampleProductVariation.copy(productVariationID: 1)
230238
insert(productVariation)
239+
insert(product)
231240
let viewModel = ProductVariationSelectorViewModel(siteID: sampleSiteID,
232241
product: product,
233242
storageManager: storageManager)
@@ -243,9 +252,10 @@ final class ProductVariationSelectorViewModelTests: XCTestCase {
243252

244253
func test_clearSelection_unselects_previously_selected_rows() {
245254
// Given
246-
let product = Product.fake().copy(productID: sampleProductID)
255+
let product = Product.fake().copy(siteID: sampleSiteID, productID: sampleProductID)
247256
let productVariation = sampleProductVariation.copy(productVariationID: 1)
248257
insert(productVariation)
258+
insert(product)
249259
let viewModel = ProductVariationSelectorViewModel(siteID: sampleSiteID,
250260
product: product,
251261
storageManager: storageManager)
@@ -280,6 +290,12 @@ private extension ProductVariationSelectorViewModelTests {
280290
productVariation.attributes = NSOrderedSet(array: storageAttributes)
281291
}
282292

293+
/// Insert a `Product` into storage.
294+
func insert(_ readOnlyProduct: Yosemite.Product) {
295+
let product = storage.insertNewObject(ofType: StorageProduct.self)
296+
product.update(with: readOnlyProduct)
297+
}
298+
283299
/// Insert an array of `ProductVariation`s into storage
284300
func insert(_ readOnlyVariations: [Yosemite.ProductVariation]) {
285301
for readOnlyVariation in readOnlyVariations {

0 commit comments

Comments
 (0)