Skip to content

Commit 4c4f41e

Browse files
committed
Add ProductVariation helper methods for generating attributes and name
1 parent 7a348f9 commit 4c4f41e

File tree

5 files changed

+61
-59
lines changed

5 files changed

+61
-59
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import Foundation
2+
import Yosemite
3+
4+
/// Yosemite.ProductVariation helper methods
5+
///
6+
extension ProductVariation {
7+
8+
/// Generates a name for the product variation, given a list of the parent product attributes, e.g. "Blue - Any Size"
9+
/// - Parameter allAttributes: A list of attributes from the parent `Product`
10+
///
11+
func generateVariationName(from allAttributes: [ProductAttribute]) -> String {
12+
let variationAttributes = generateVariationAttributes(from: allAttributes)
13+
return variationAttributes.map { $0.nameOrValue }.joined(separator: " - ")
14+
}
15+
16+
/// Generates the variation attributes, given a list of the parent product attributes.
17+
/// - Parameter allAttributes: A list of attributes from the parent `Product`
18+
///
19+
func generateVariationAttributes(from allAttributes: [ProductAttribute]) -> [VariationAttributeViewModel] {
20+
return allAttributes
21+
.sorted(by: { (lhs, rhs) -> Bool in
22+
lhs.position < rhs.position
23+
})
24+
.map { productAttribute -> VariationAttributeViewModel in
25+
guard let variationAttribute = attributes.first(where: { $0.id == productAttribute.attributeID && $0.name == productAttribute.name }) else {
26+
return VariationAttributeViewModel(name: productAttribute.name)
27+
}
28+
return VariationAttributeViewModel(productVariationAttribute: variationAttribute)
29+
}
30+
}
31+
}

WooCommerce/Classes/ViewRelated/Orders/Order Creation/ProductsSection/AddProductVariationToOrderViewModel.swift

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ final class AddProductVariationToOrderViewModel: ObservableObject {
4444
/// View models for each product variation row
4545
///
4646
var productVariationRows: [ProductRowViewModel] {
47-
productVariations.map { .init(productVariation: $0, name: createVariationName(for: $0), canChangeQuantity: false) }
47+
productVariations.map { .init(productVariation: $0, name: $0.generateVariationName(from: productAttributes), canChangeQuantity: false) }
4848
}
4949

5050
/// Closure to be invoked when a product variation is selected
@@ -124,18 +124,6 @@ final class AddProductVariationToOrderViewModel: ObservableObject {
124124
}
125125
onVariationSelected?(selectedVariation)
126126
}
127-
128-
/// Creates a name for a provided variation using all available product attributes, e.g. "Blue - Any Size"
129-
///
130-
func createVariationName(for variation: ProductVariation) -> String {
131-
let variationAttributes = productAttributes.map { attribute -> VariationAttributeViewModel in
132-
guard let variationAttribute = variation.attributes.first(where: { $0.id == attribute.attributeID && $0.name == attribute.name }) else {
133-
return VariationAttributeViewModel(name: attribute.name)
134-
}
135-
return VariationAttributeViewModel(productVariationAttribute: variationAttribute)
136-
}
137-
return variationAttributes.map { $0.nameOrValue }.joined(separator: " - ")
138-
}
139127
}
140128

141129
// MARK: - SyncingCoordinatorDelegate & Sync Methods

WooCommerce/Classes/ViewRelated/Products/Edit Product/EditableProductVariationModel.swift

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@ final class EditableProductVariationModel {
66

77
let allAttributes: [ProductAttribute]
88

9-
private lazy var variationAttributes: [VariationAttributeViewModel] = {
10-
return generateVariationAttributes(productVariationAttributes: productVariation.attributes, allAttributes: allAttributes)
11-
}()
12-
139
init(productVariation: ProductVariation, allAttributes: [ProductAttribute], parentProductSKU: String?) {
1410
self.allAttributes = allAttributes
1511

@@ -21,23 +17,6 @@ final class EditableProductVariationModel {
2117
}
2218
}
2319

24-
private extension EditableProductVariationModel {
25-
26-
func generateVariationAttributes(productVariationAttributes: [ProductVariationAttribute],
27-
allAttributes: [ProductAttribute]) -> [VariationAttributeViewModel] {
28-
return allAttributes
29-
.sorted(by: { (lhs, rhs) -> Bool in
30-
lhs.position < rhs.position
31-
})
32-
.map { attribute -> VariationAttributeViewModel in
33-
guard let variationAttribute = productVariation.attributes.first(where: { $0.id == attribute.attributeID && $0.name == attribute.name }) else {
34-
return VariationAttributeViewModel(name: attribute.name)
35-
}
36-
return VariationAttributeViewModel(productVariationAttribute: variationAttribute)
37-
}
38-
}
39-
}
40-
4120
extension EditableProductVariationModel: ProductFormDataModel, TaxClassRequestable {
4221
var siteID: Int64 {
4322
productVariation.siteID
@@ -48,7 +27,7 @@ extension EditableProductVariationModel: ProductFormDataModel, TaxClassRequestab
4827
}
4928

5029
var name: String {
51-
variationAttributes.map { $0.nameOrValue }.joined(separator: " - ")
30+
productVariation.generateVariationName(from: allAttributes)
5231
}
5332

5433
var description: String? {

WooCommerce/WooCommerce.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,6 +1194,7 @@
11941194
CCDC49ED24000533003166BA /* TestCredentials.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCDC49EC24000533003166BA /* TestCredentials.swift */; };
11951195
CCE4CD172667EBB100E09FD4 /* ShippingLabelPaymentMethodsViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCE4CD162667EBB100E09FD4 /* ShippingLabelPaymentMethodsViewModelTests.swift */; };
11961196
CCE4CD282669324300E09FD4 /* ShippingLabelPaymentMethodsTopBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCE4CD272669324300E09FD4 /* ShippingLabelPaymentMethodsTopBanner.swift */; };
1197+
CCEC256A27B581E800EF9FA3 /* ProductVariation+Woo.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCEC256927B581E800EF9FA3 /* ProductVariation+Woo.swift */; };
11971198
CCF87BBE279047BC00461C43 /* InfiniteScrollList.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCF87BBD279047BC00461C43 /* InfiniteScrollList.swift */; };
11981199
CCF87BC02790582500461C43 /* AddProductVariationToOrder.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCF87BBF2790582400461C43 /* AddProductVariationToOrder.swift */; };
11991200
CCFC00B523E9BD1500157A78 /* ScreenshotCredentials.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCFC00B423E9BD1500157A78 /* ScreenshotCredentials.swift */; };
@@ -2814,6 +2815,7 @@
28142815
CCDC49F224006130003166BA /* UITests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; name = UITests.xctestplan; path = WooCommerceUITests/UITests.xctestplan; sourceTree = SOURCE_ROOT; };
28152816
CCE4CD162667EBB100E09FD4 /* ShippingLabelPaymentMethodsViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingLabelPaymentMethodsViewModelTests.swift; sourceTree = "<group>"; };
28162817
CCE4CD272669324300E09FD4 /* ShippingLabelPaymentMethodsTopBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingLabelPaymentMethodsTopBanner.swift; sourceTree = "<group>"; };
2818+
CCEC256927B581E800EF9FA3 /* ProductVariation+Woo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProductVariation+Woo.swift"; sourceTree = "<group>"; };
28172819
CCF87BBD279047BC00461C43 /* InfiniteScrollList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfiniteScrollList.swift; sourceTree = "<group>"; };
28182820
CCF87BBF2790582400461C43 /* AddProductVariationToOrder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddProductVariationToOrder.swift; sourceTree = "<group>"; };
28192821
CCFC00B423E9BD1500157A78 /* ScreenshotCredentials.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreenshotCredentials.swift; sourceTree = "<group>"; };
@@ -5941,6 +5943,7 @@
59415943
CECC759423D6057E00486676 /* OrderItem+Woo.swift */,
59425944
CECC759623D607C900486676 /* OrderItemRefund+Woo.swift */,
59435945
7435E58D21C0151B00216F0F /* OrderNote+Woo.swift */,
5946+
CCEC256927B581E800EF9FA3 /* ProductVariation+Woo.swift */,
59445947
45E3C8F225E7D30300102E84 /* ShippingLabelAddress+Woo.swift */,
59455948
D8C2A28723190B2300F503E9 /* StorageProductReview+Woo.swift */,
59465949
B59D1EE92190AE96009D1978 /* StorageNote+Woo.swift */,
@@ -8570,6 +8573,7 @@
85708573
45DB70662614CE3F0064A6CF /* Decimal+Helpers.swift in Sources */,
85718574
02E8B17C23E2C78A00A43403 /* ProductImageStatus.swift in Sources */,
85728575
0259D5FF2581F3FA003B1CD6 /* ShippingLabelPaperSizeOptionsViewController.swift in Sources */,
8576+
CCEC256A27B581E800EF9FA3 /* ProductVariation+Woo.swift in Sources */,
85738577
02EA6BFA2435E92600FFF90A /* KingfisherImageDownloader+ImageDownloadable.swift in Sources */,
85748578
7E7C5F8F2719BA7300315B61 /* ProductCategoryCellViewModel.swift in Sources */,
85758579
DEC2962326BD4E6E005A056B /* ShippingLabelCustomsFormInput.swift in Sources */,

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

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,15 @@ class AddProductVariationToOrderViewModelTests: XCTestCase {
2424
super.tearDown()
2525
}
2626

27-
func test_view_model_adds_product_variation_rows_with_unchangeable_quantity() {
27+
func test_view_model_adds_product_variation_rows_with_expected_values() {
2828
// Given
29-
let product = Product.fake().copy(productID: sampleProductID)
30-
let productVariation = ProductVariation.fake().copy(siteID: sampleSiteID, productID: sampleProductID, purchasable: true)
29+
let product = Product.fake().copy(productID: sampleProductID,
30+
attributes: [ProductAttribute.fake().copy(siteID: sampleSiteID, attributeID: 1, name: "Color", variation: true),
31+
ProductAttribute.fake().copy(siteID: sampleSiteID, attributeID: 2, name: "Size", variation: true)])
32+
let productVariation = ProductVariation.fake().copy(siteID: sampleSiteID,
33+
productID: sampleProductID,
34+
attributes: [ProductVariationAttribute(id: 1, name: "Color", option: "Blue")],
35+
purchasable: true)
3136
insert(productVariation)
3237

3338
// When
@@ -39,6 +44,7 @@ class AddProductVariationToOrderViewModelTests: XCTestCase {
3944
let productVariationRow = viewModel.productVariationRows[0]
4045
XCTAssertFalse(productVariationRow.canChangeQuantity,
4146
"Product variation row canChangeQuantity property should be false but is true instead")
47+
XCTAssertEqual(productVariationRow.name, "Blue - Any Size")
4248
}
4349

4450
func test_product_variation_rows_only_include_purchasable_product_variations() {
@@ -61,20 +67,6 @@ class AddProductVariationToOrderViewModelTests: XCTestCase {
6167
"Product variation rows include non-purchasable product variation")
6268
}
6369

64-
func test_createVariationName_creates_expected_name_for_product_variation_rows() {
65-
// Given
66-
let product = Product.fake().copy(attributes: [ProductAttribute.fake().copy(siteID: sampleSiteID, attributeID: 1, name: "Color", variation: true),
67-
ProductAttribute.fake().copy(siteID: sampleSiteID, attributeID: 2, name: "Size", variation: true)])
68-
let viewModel = AddProductVariationToOrderViewModel(siteID: sampleSiteID, product: product)
69-
let productVariation = ProductVariation.fake().copy(attributes: [ProductVariationAttribute(id: 1, name: "Color", option: "Blue")])
70-
71-
// When
72-
let variationName = viewModel.createVariationName(for: productVariation)
73-
74-
// Then
75-
XCTAssertEqual(variationName, "Blue - Any Size")
76-
}
77-
7870
func test_scrolling_indicator_appears_only_during_sync() {
7971
// Given
8072
let product = Product.fake()
@@ -190,16 +182,24 @@ class AddProductVariationToOrderViewModelTests: XCTestCase {
190182
// MARK: - Utils
191183
private extension AddProductVariationToOrderViewModelTests {
192184
/// Insert a `ProductVariation` into storage
193-
func insert(_ readOnlyProduct: Yosemite.ProductVariation) {
194-
let product = storage.insertNewObject(ofType: StorageProductVariation.self)
195-
product.update(with: readOnlyProduct)
185+
func insert(_ readOnlyVariation: Yosemite.ProductVariation) {
186+
let productVariation = storage.insertNewObject(ofType: StorageProductVariation.self)
187+
productVariation.update(with: readOnlyVariation)
188+
189+
// Inserts the attributes from the read-only product variation.
190+
var storageAttributes = [StorageAttribute]()
191+
for readOnlyAttribute in readOnlyVariation.attributes {
192+
let newStorageAttribute = storage.insertNewObject(ofType: Storage.GenericAttribute.self)
193+
newStorageAttribute.update(with: readOnlyAttribute)
194+
storageAttributes.append(newStorageAttribute)
195+
}
196+
productVariation.attributes = NSOrderedSet(array: storageAttributes)
196197
}
197198

198199
/// Insert an array of `ProductVariation`s into storage
199-
func insert(_ readOnlyProducts: [Yosemite.ProductVariation]) {
200-
for readOnlyProduct in readOnlyProducts {
201-
let product = storage.insertNewObject(ofType: StorageProductVariation.self)
202-
product.update(with: readOnlyProduct)
200+
func insert(_ readOnlyVariations: [Yosemite.ProductVariation]) {
201+
for readOnlyVariation in readOnlyVariations {
202+
insert(readOnlyVariation)
203203
}
204204
}
205205
}

0 commit comments

Comments
 (0)