-
Notifications
You must be signed in to change notification settings - Fork 10.7k
Add the Cost of Goods Sold related code and REST APIs for the product class #51675
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
Conversation
The UI for a non-legacy feature was showing up greyed out
("UI disabled") when the setting that controls the feature
was off ("feature disabled").
…ses. Also update the data stores appropriately. COGS values will be stored in a "_cogs_total_value" product meta key, but only when the value is not zero. For variations, a flag indicating if the COGS value overrides the parent value will be stored in a "_cogs_value_overrides_parent" product meta key, but only when the value is true (stored as "yes").
(get/create/modify products and variations endpoints).
Test using WordPress PlaygroundThe changes in this pull request can be previewed and tested using a WordPress Playground instance. Test this pull request with WordPress Playground. Note that this URL is valid for 30 days from when this comment was last updated. You can update it by closing/reopening the PR or pushing a new commit. |
|
Oh, we are so looking forward to have this in the core. One small note:
Zero is a perfectly fine value for COGS - when you are given free items from a vendor you are (at least in sweden) not allowed to keep any other value than 0 in your books. I think you should allow zero here. |
Hi, I think I did not explain this correctly. Of course zero will be an allowed value for COGS and in fact it's the value that all products will get by default. What I meant is that when the value is zero, no |
|
Ah, got it. Sorry about misunderstanding :)
Den fre 27 sep. 2024 kl 08:42 skrev Néstor Soriano ***@***.***
…:
The value set by set_cogs_value is stored as product meta using the
_cogs_total_value key, but only if the feature is enabled and the value is
not zero.
Zero is a perfectly fine value for COGS
Hi, I think I did not explain this correctly. Of course zero will be an
allowed value for COGS and in fact it's the value that all products will
get by default. What I meant is that when the value is zero, no
_cogs_total_value key will be stored in the meta table for he product;
but then, when loading the product the code will detect that the meta value
is missing and will assume a value of zero. This way there's no need to do
an initial filling of the meta table with zero values for all the existing
products.
—
Reply to this email directly, view it on GitHub
<#51675 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AW3Q32URBAOJJO2GGITKPWDZYT46JAVCNFSM6AAAAABO2G2R4CVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGNZYGUYTINJYGM>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
|
Hi @barryhughes, Apart from reviewing the code changes, please make sure to review the testing instructions and verify that relevant tests (E2E, Unit, Integration, etc.) have been added or updated as needed. You can follow this guide to find out what good testing instructions should look like: |
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.
A note on redundancy and future-proofing [...]
I think I understand, yet it still seems like a complex interface and, at least for me—and I may be the outlier—not immediately intuitive as a result. Are there other possibilities worth exploring?
# I realize `mixed` and enums are both off-the-table right now,
# this is just meant to be illustrative.
set_cogs( mixed $value, Cogs_Method $method = Cogs_Method::FIXED_COST ): voidOr possibly:
# Where type CostOfGoodsSold lets us describe various possibilities.
set_cogs( CostOfGoodsSold $cost_of_goods_sold ): voidTo be super clear, I'm not strongly opposed to what we have. Yet, once it enters production, the API will, to a large extent, become frozen ... so it feels like it's worth a little time ensuring it's as comfortable and intuitive as we can make it, in addition to offering the necessary flexibility and future-proofing.
- CogwsAwareTrait extracted from the CogsAwareRestControllerTrait, it contains only the cogs_is_enabled method. - cogs_is_enabled has now a string parameter defaulting to null, when it's not null and the feature is disabled, a doing_it_wrong will be thrown (using the argument value as the function name). - All the get/set cogs value methods in the base product class now execute cogs_is_enabled with a non-null parameter. - New get_cogs_effective_value_core method added, consistent with get_cogs_total_value_core.
Actually I was thinking that the method to set the value would evolve like this after the MVP: function set_cogs_value( float $value, string $value_type = null )This would be paired with the concept of COGS categories, where a product belonging to a given category would mean that it would have a fixed set (defined per category) of COGS value types. The quantity type of each value type would be fixed (part of the definition of the category). Additionally, a
Of course, but on the other hand, while the feature is experimental we have a bit more of flexibility to make changes to the public API (and any possible design issue is more likely to surface once code begins to be merged and thus tested in real(ish) scenarios). |
Do we/should we do anything else to make it clear these (public, non-internal) methods may be subject to change? Supplement the 'warning' messages in the docblocks? Not sure if it's necessary, just being cautious. |
barryhughes
left a comment
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.
Left a comment asking how we might make it clear the API is unstable (in the sense, it may be refined before the feature leaves the experimental status), but beyond that it tests per instructions 👍🏼
I understand that this is kind of implied by the fact that it's listed in the experimental features list in the features page, with the section described as "These features are either experimental or incomplete". That said, at the very least we should explicitly mention that when the time to publicly announce the feature MVP comes. |
Changes proposed in this Pull Request:
This pull request is the beginning of the implementation of a Cost of Goods Sold feature in WooCommerce, it introduces the code and REST API changes to support programmatically setting and getting one single cost value for any product.
Changes in code API
FeaturesController):cost_of_goods_soldWC_Abstract_Legacy_Productclass:set_cogs_value( float $value ): voidget_cogs_value(): floatget_cogs_effective_value(): floatget_cogs_total_value(): floatWC_Product_Variationclass:get_cogs_value_overrides_parent(): boolset_cogs_value_overrides_parent( bool $value )WC_Product_Data_Store_CPTandWC_Product_Variation_Data_Store_CPTget the modifications needed to persist the new values (see below).Currently
get_cogs_value,get_cogs_effective_valueandget_cogs_total_valuereturn all the same value, with one exception: in products that are variations,get_cogs_effective_valueandget_cogs_total_valuereturn the stored value for the variation added to the stored value for the parent product, unlessset_cogs_value_overrides_parent(true)was executed.Storage
The value set by
set_cogs_valueis stored as product meta using the_cogs_total_valuekey, but only if the feature is enabled and the value is not zero (a missing meta value for a product will be treated as equivalent to a value of zero).The value set by
set_cogs_value_overrides_parentis stored as product meta using the_cogs_value_overrides_parentkey, but only if the feature is enabled and the value istrue(a missing meta value for a product will be treated as equivalent to a value offalse).Changes in REST API
The following is added to the REST API schema for products and variations (
/wp-json/wc/v3/products/<product id>and/wp-json/wc/v3/products/<product id>/variationsendpoints, for bothGETandPOSTrequests):{ "cost_of_goods_sold": { "values": [ { "defined_value": <float> "effective_value": <float> } ], "total_value": <float>, "defined_value_overrides_parent": <bool> } }defined_value_overrides_parentis present only for variations.effective_valueandtotal_valueare read-only fields.In principle, for
POSTendpoints only one object with values is expected to be found insidevalues. However the endpoints code will add upp thedefined_valuess of all the objects if more than one is supplied, and the result will be the value set for the product.The
POSTendpoints will not modify the current value of a product being modified if novalueskey (or nocost_of_goods_soldkey whatsoever) is present, but an emptyvaluesarray will set a value of zero. Similarly, for variations the "value overrides parent" flag will not be modified if nodefined_value_overrides_parentis present. Default values for new products are a cost of zero and no override for variations.Hooks
The following filters are introduced:
woocommerce_get_cogs_total_value: to customize the value that gets returned byget_cogs_total_value.woocommerce_load_cogs_value: to modify the value that gets loaded from the database for a given product.woocommerce_load_cogs_overrides_parent_value_flag: same as above but for the value override flag.woocommerce_save_cogs_value: to modify the value that gets saved to the database for a given product, or to suppress the value saving altogether.woocommerce_save_cogs_overrides_parent_value_flag: same as above but for the value override flag.How to test the changes in this Pull Request:
Create a variable product with at least one variation. Let's assume their ids are
$product_idand$variation_id.You also need to enable the feature. Go to WooCommerce - Settings - Advanced - Features, check the box for "Cost of Goods Sold" and save.
Code API changes
For your convenience it's recommended to test these steps from a
wp shell.$variation_idinstead of$product_idand using a value of 20.5 instead of 12.34. The results should be the same except that the effective and total values will have the parent value added:Testing the REST API
Perform
GETrequests to the/wp-json/wc/v3/products/<product id>,/wp-json/wc/v3/products/<variation id>and/wp-json/wc/v3/products/<product id>/variations/<variation id>and verify that you get the extracost_of_goods_solditem with the appropriate information. For the variation test with and without the "overrides parent" flag set.Now try a
POSTrequest to/wp-json/wc/v3/products/<product id>with the following body, and verify (using the code API, theGETendpoint, or querying the database) that the related information is updated accordingly (the final value should be 32.84):{ "cost_of_goods_sold": { "values": [ { "defined_value": 12.34 }, { "defined_value": 20.5 } ] } }Now try two
POSTrequest to/wp-json/wc/v3/products/<product id>/variations/<variation id>with the following bodies, verify that in each case only the appropriate information (value for the first, overrides flag for the second) is updated:{ "cost_of_goods_sold": { "values": [ { "defined_value": 111 } ] } }{ "cost_of_goods_sold": { "defined_value_overrides_parent": <true or false> } }Now try the following body in a
POSTrequest to either the product or the variation endpoint, and verify that the cost value is set to zero:{ "cost_of_goods_sold": { "values": [] } }Finally, try
OPTIONSrequests on the endpoints and verify that the extended schema information returned is accurate.Testing the filters
Here's scaffolding code to test the filters, you can add it at the end of
woocommerce.phpor as a code snippet. Try changing the return value of one filter at a time, and verifying via code API or REST API that the result is as expected:Testing with the feature disabled
Disable the feature in the features settings page and verify that:
cost_of_goods_soldkey.cost_of_goods_soldkey passed to aPOSTREST API request for a product will be ignored (it will not cause any change in the product).OPTIONSrequests don't include acost_of_goods_soldkey in the returned schema.Note that disabling the feature won't delete any product metadata that was created while the feature was enabled.
A note on redundancy and future-proofing
It may seem that having three different cost values (defined, effective, total) is redundant. And it is at the current stage of the project, but these three values are added to support future extension of the feature while keeping backwards compatibility. More precisely, the following additions might be added at a later point:
This is also the reason of the seemingly convoluted design of the
cost_of_goods_solditem in the REST API schema (a values array rather than one single value).Changelog entry
Changelog Entry Details
Significance
Type
Message
Changelog Entry Comment
Comment