Woocommerce: Add an object to represent a discount.

Created on 14 Apr 2018  路  3Comments  路  Source: woocommerce/woocommerce

WooCommerce doesn't have an object to represent a discount of an order. Coupons are available as an object, but they are very specific and not applicable to the use-cases you would use a discount object for.

The context for this is that on yoast.com we currently have 5 ways that a discount can occur:

  1. A single product is on sale. A sale price is essentially always a discount. For subscription purposes, you always want to know the original price. This is probably why WooCommerce has three different meta fields to keep track of:

    a. The current price.

    b. The sale price.

    c. The original price.

  2. A coupon code.

  3. All products on the whole site are discounted by a specific percentual amount.

  4. A customer buys a certain amount of the same plugin which results in a certain amount of percentual discount.

  5. A customer buys a bundle which gives them the right to a certain percentual discount.

These are all implemented in a custom way. The first two is implemented by WooCommerce itself. 3 is implemented by our own custom code. 4. is implemented by the WooCommerce bulk discount add-on. 5. is implemented using WooCommerce product bundles.

This means that this code conflicts in unique ways and they all have to have code to make sure they play nice with each other. I am proposing a discount object that will streamline all of this. With that object in place the order of these can be handled in a clear way and conflicts will be less painful.

This is also important for reporting. Currently the bulk discount is sometimes seen as a sale which really throws off our reporting.

Code architecture

I have thought about how the code could look like and I think it would make sense to have an interface for this. All the different plugins could implement this interface to add a another way to have a discount. The interface should have a method to get the price after the discount. The method could be named apply.

This also means that you then can have an aggregate discount that combines all the discounts that apply to an order/line item.

I don't have the capacity to write this code, but I will be available to do code reviews.

Prerequisites

  • [x] I have searched for similar issues in both open and closed tickets and cannot find a duplicate
  • [x] The issue still exists against the latest master branch of WooCommerce on Github (this is not the same version as on WordPress.org!)
  • [x] I have attempted to find the simplest possible steps to reproduce the issue
  • [ ] I have included a failing test as a pull request (Optional)
won't fix enhancement votes needed

Most helpful comment

@atimmer Hi Anton

A single product is on sale. A sale price is essentially always a discount.

In most cases yes, but not always. e.g. when changing the price vs RRP. I've certainly never seen a store where sale prices have been reflected in the cart like real coupon based discounts...

All products on the whole site are discounted by a specific percentual amount.
A customer buys a certain amount of the same plugin which results in a certain amount of percentual discount.
A customer buys a bundle which gives them the right to a certain percentual discount.

These seems to be the same thing in terms of what they are/what they do. They take a product price, run some calculations, and adjust the product price before the cart does it's own calculations.

This means that this code conflicts in unique ways and they all have to have code to make sure they play nice with each other. I am proposing a discount object that will streamline all of this. With that object in place the order of these can be handled in a clear way and conflicts will be less painful.

It won't be possible for core to handle these types of calculations for plugins - they will all have their own logic and ways discounts need to occur.

I also don't think coupon based discounts should be mixed with the product price modification type discounts those plugins implement. Coupons should really apply last. And unlike the examples you have where they discount the line items and show discounts per line (even though technically coupons discount the line items) they are presented as discounts on the cart as a whole.

For the types of discount you're proposing, I'm assuming they currently work something as follows:

  • Price for a product is loaded from DB
  • Discounts are calculated based on the criteria of the user or product
  • The price of the product is adjusted to suit

You're correct there is no way in core to track or store these types of discounts.

I'm not sure how _"Currently the bulk discount is sometimes seen as a sale which really throws off our reporting."_ would happen without reviewing plugin code. As long as the prices are modified correctly, line totals + order totals will always be correct for reports. Perhaps there is some usage of woocommerce_get_discounted_price going on which affect line item costs and apply after coupons..

I don't have the capacity to write this code, but I will be available to do code reviews.

I don't think we'll be able to prioritise this one either as there doesn't appear to be much demand. Plugins can do what they need under the current system. Whilst a refactor could be an improvement, there is also a potential to break the current system.

For this reason I'm going to mark this as wontfix for now. If we decide to work on something which needs this (product discounts extension? @avivapinchas @bor0) that would be an ideal use case to build something new in core to support it, but without that use case it probably doesn't make sense for us to guess what's needed as that could make things worse :)

If plugin developers using the current system wanted to join forces and agree/contribute a unified system for core they can all benefit from that would be good. Like you, we'd be happy to code review any proposals :) Could raise this in dev chat to see if folks are interested?

Thanks cc @claudiulodro

All 3 comments

@atimmer Hi Anton

A single product is on sale. A sale price is essentially always a discount.

In most cases yes, but not always. e.g. when changing the price vs RRP. I've certainly never seen a store where sale prices have been reflected in the cart like real coupon based discounts...

All products on the whole site are discounted by a specific percentual amount.
A customer buys a certain amount of the same plugin which results in a certain amount of percentual discount.
A customer buys a bundle which gives them the right to a certain percentual discount.

These seems to be the same thing in terms of what they are/what they do. They take a product price, run some calculations, and adjust the product price before the cart does it's own calculations.

This means that this code conflicts in unique ways and they all have to have code to make sure they play nice with each other. I am proposing a discount object that will streamline all of this. With that object in place the order of these can be handled in a clear way and conflicts will be less painful.

It won't be possible for core to handle these types of calculations for plugins - they will all have their own logic and ways discounts need to occur.

I also don't think coupon based discounts should be mixed with the product price modification type discounts those plugins implement. Coupons should really apply last. And unlike the examples you have where they discount the line items and show discounts per line (even though technically coupons discount the line items) they are presented as discounts on the cart as a whole.

For the types of discount you're proposing, I'm assuming they currently work something as follows:

  • Price for a product is loaded from DB
  • Discounts are calculated based on the criteria of the user or product
  • The price of the product is adjusted to suit

You're correct there is no way in core to track or store these types of discounts.

I'm not sure how _"Currently the bulk discount is sometimes seen as a sale which really throws off our reporting."_ would happen without reviewing plugin code. As long as the prices are modified correctly, line totals + order totals will always be correct for reports. Perhaps there is some usage of woocommerce_get_discounted_price going on which affect line item costs and apply after coupons..

I don't have the capacity to write this code, but I will be available to do code reviews.

I don't think we'll be able to prioritise this one either as there doesn't appear to be much demand. Plugins can do what they need under the current system. Whilst a refactor could be an improvement, there is also a potential to break the current system.

For this reason I'm going to mark this as wontfix for now. If we decide to work on something which needs this (product discounts extension? @avivapinchas @bor0) that would be an ideal use case to build something new in core to support it, but without that use case it probably doesn't make sense for us to guess what's needed as that could make things worse :)

If plugin developers using the current system wanted to join forces and agree/contribute a unified system for core they can all benefit from that would be good. Like you, we'd be happy to code review any proposals :) Could raise this in dev chat to see if folks are interested?

Thanks cc @claudiulodro

This seems to be in line with some of the conflicts we've had for Account Funds/Store Credit.

cc @laurendavissmith @madeincosmos

How does one code bulk discounts with current system?

If one touches woocommerce_calculate_totals and woocommerce_calculated_total then things seem to be ok, up to the point when an admin clicks "Recalculate Totals" in wp-admin, when wc_save_order_items() breaks any custom applied discount.

Another way (that I haven't yet tried) seems to be the woocommerce_get_discounted_price filter, but the big fat "this is legacy" note there makes me a bit reluctant to use it.

P.S. Someone has tagged this as "good first issue"? ROFL.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

aonzzung picture aonzzung  路  3Comments

joelwills picture joelwills  路  3Comments

mikejolley picture mikejolley  路  3Comments

tushonline picture tushonline  路  3Comments

pawelkmpt picture pawelkmpt  路  3Comments