-
Notifications
You must be signed in to change notification settings - Fork 117
Dynamic Dashboard: Integrate new endpoint for product stock in Networking layer #12756
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
708f815
Add ProductStock model
itsmeichigo 3b78289
Regenerate fakes
itsmeichigo bd4c8d8
Add mapper for ProductStock
itsmeichigo c4fefc8
Add new remote endpoint for loading product by stock status
itsmeichigo 3300960
Merge branch 'trunk' into feat/12748-integrate-stock-endpoint
itsmeichigo 26a78f3
Send parameters to the stock request
itsmeichigo 6cdef8f
Update MockProductsRemote
itsmeichigo 61673b9
Fix build failure for MockProductsRemote
itsmeichigo 52ae7f8
Update orders for properties of DashboardCard to avoid rake generate …
itsmeichigo e9447dc
Add name to ProductStock
itsmeichigo dc95b5b
Regenerate fakes
itsmeichigo 8ca7bab
Add tests for ProductStockListMapper
itsmeichigo e12f81b
Add tests to ProductsRemote
itsmeichigo 32ceaec
Add tests for edge cases
itsmeichigo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import Foundation | ||
|
||
/// Mapper: `[ProductStock]` | ||
/// | ||
struct ProductStockListMapper: Mapper { | ||
/// Site Identifier associated to the products that will be parsed. | ||
/// | ||
/// We're injecting this field via `JSONDecoder.userInfo` because SiteID is not returned in any of the Product Endpoints. | ||
/// | ||
let siteID: Int64 | ||
|
||
/// (Attempts) to convert a dictionary into `[ProductStock]`. | ||
/// | ||
func map(response: Data) throws -> [ProductStock] { | ||
let decoder = JSONDecoder() | ||
decoder.userInfo = [ | ||
.siteID: siteID | ||
] | ||
if hasDataEnvelope(in: response) { | ||
return try decoder.decode(ProductStockListEnvelope.self, from: response).items | ||
} else { | ||
return try decoder.decode([ProductStock].self, from: response) | ||
} | ||
} | ||
} | ||
|
||
|
||
/// ProductStockListEnvelope Disposable Entity: | ||
/// Load Product stock list endpoint returns the coupon in the `data` key. | ||
/// This entity allows us to parse all the things with JSONDecoder. | ||
/// | ||
private struct ProductStockListEnvelope: Decodable { | ||
let items: [ProductStock] | ||
|
||
private enum CodingKeys: String, CodingKey { | ||
case items = "data" | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import Foundation | ||
import Codegen | ||
|
||
/// Represents stock details for a Product. | ||
/// | ||
public struct ProductStock: Decodable, GeneratedCopiable, Equatable, GeneratedFakeable { | ||
|
||
public let siteID: Int64 | ||
public let productID: Int64 | ||
public let name: String | ||
|
||
public let sku: String? | ||
public let manageStock: Bool | ||
public let stockQuantity: Decimal? // Core API reports Int or null; some extensions allow decimal values as well | ||
public let stockStatusKey: String // instock, outofstock, backorder | ||
|
||
public var productStockStatus: ProductStockStatus { | ||
return ProductStockStatus(rawValue: stockStatusKey) | ||
} | ||
|
||
public init(siteID: Int64, | ||
productID: Int64, | ||
name: String, | ||
sku: String?, | ||
manageStock: Bool, | ||
stockQuantity: Decimal?, | ||
stockStatusKey: String) { | ||
self.siteID = siteID | ||
self.productID = productID | ||
self.name = name | ||
self.sku = sku | ||
self.manageStock = manageStock | ||
self.stockQuantity = stockQuantity | ||
self.stockStatusKey = stockStatusKey | ||
} | ||
|
||
/// The public initializer. | ||
/// | ||
public init(from decoder: Decoder) throws { | ||
guard let siteID = decoder.userInfo[.siteID] as? Int64 else { | ||
throw ProductDecodingError.missingSiteID | ||
} | ||
|
||
let container = try decoder.container(keyedBy: CodingKeys.self) | ||
let productID = try container.decode(Int64.self, forKey: .productID) | ||
let name = try container.decode(String.self, forKey: .name) | ||
|
||
// Even though a plain install of WooCommerce Core provides String values, | ||
// some plugins alter the field value from String to Int or Decimal. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great research to find how plugins might alter this value. |
||
let sku = container.failsafeDecodeIfPresent(targetType: String.self, | ||
forKey: .sku, | ||
alternativeTypes: [.decimal(transform: { NSDecimalNumber(decimal: $0).stringValue })]) | ||
|
||
// Even though the API docs claim `manageStock` is a bool, it's possible that `"parent"` | ||
// could be returned as well (typically with variations) — we need to account for this. | ||
// A "parent" value means that stock mgmt is turned on + managed at the parent product-level, therefore | ||
// we need to set this var as `true` in this situation. | ||
// See: https://github.com/woocommerce/woocommerce-ios/issues/884 for more deets | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great research here as well. |
||
let manageStock = container.failsafeDecodeIfPresent(targetType: Bool.self, | ||
forKey: .manageStock, | ||
alternativeTypes: [ | ||
.string(transform: { value in | ||
// A bool could not be parsed — check if "parent" is set, and if so, set manageStock to | ||
// `true` | ||
value.lowercased() == Values.manageStockParent ? true : false | ||
}) | ||
]) ?? false | ||
|
||
// Even though WooCommerce Core returns Int or null values, | ||
// some plugins alter the field value from Int to Decimal or String. | ||
// We handle this as an optional Decimal value. | ||
let stockQuantity = container.failsafeDecodeIfPresent(decimalForKey: .stockQuantity) | ||
|
||
let stockStatusKey = try container.decode(String.self, forKey: .stockStatusKey) | ||
|
||
self.init(siteID: siteID, | ||
productID: productID, | ||
name: name, | ||
sku: sku, | ||
manageStock: manageStock, | ||
stockQuantity: stockQuantity, | ||
stockStatusKey: stockStatusKey) | ||
} | ||
} | ||
|
||
/// Defines all of the ProductStock CodingKeys | ||
/// | ||
private extension ProductStock { | ||
|
||
enum CodingKeys: String, CodingKey { | ||
case productID = "id" | ||
case name | ||
case sku = "sku" | ||
|
||
case manageStock = "manage_stock" | ||
case stockQuantity = "stock_quantity" | ||
case stockStatusKey = "stock_status" | ||
} | ||
|
||
// Decoding Errors | ||
enum DecodingError: Error { | ||
case missingSiteID | ||
} | ||
|
||
enum Values { | ||
static let manageStockParent = "parent" | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍🏼 TIL about getting siteID this way.