OCA / sale-workflow

Odoo Sales, Workflow and Organization
GNU Affero General Public License v3.0
295 stars 1.03k forks source link

[RFC][16.0] New module to apply bulk discount on sale order line when the product quantity matches the size of the package #2587

Open carmenbianca opened 1 year ago

carmenbianca commented 1 year ago

Is your feature request related to a problem? Company A wants to sell products to clients. For Company A, it is cheaper and more efficient to sell by bulk. To encourage clients to buy products in bulk (e.g., buy a pallet of 100 products), they want to apply a bulk discount.

Describe the solution you'd like A new module sale_package_bulk_discount. The module can be summarised as follows:

When a product is sold in bulk, that product is sold at a discount defined on the package type (e.g. pallet). For this discount to apply, the customer must purchase an amount of products equal to a multiple of the package's quantity. Any quantity of products exceeding that amount is sold at full price.

For instance, if a pallet can hold 100 products, then the discount applies to 100, 200, or 1000 products sold. If the customer buys 50 products, the discount does not apply. If the customer buys 150 products, then the customer gets the discount for the first 100 products, but not the last 50 products.

Describe alternatives you've considered None.

Additional context I imagine the workflow of the module to work kind of like this:

  1. Set base price on product. Let's assume €10.
  2. Set a percentage discount on the pallet package type. Let's assume 20% (resulting in €8 for the example product).
  3. On a sale order line for our product, select a pallet package. Let's assume that it holds 100 products.
  4. Insert a quantity of products. Let's assume 101.
  5. Two things happen simultaneously:
    1. The quantity of the selected line goes back to 100. The price on this line becomes €8.
    2. A new sale order line is created with a quantity of 1 (not sure if it has a package?). The price on this line becomes €10.

I volunteer to write this module myself.

Pinging some potentially interested parties (chiefly Akretion & Camp2camp):

@bealdav @grindtildeath @simahawk

legalsylvain commented 1 year ago

Hi @carmenbianca. I have similar needs in my company, expressed differently. I didn't work on that topic for the time being, and I'm interested to talk with people interested.

regarding your proposal :

It avoid to set a discount on the package. What do you think ?

Regarding my thought, I was thinking on the following implementation where I was more interested in charging for unpacking. because that is an extra work to open a package. Use case : sell cheese. A tome of cheese costs 450€ / 30kg. If the customer wants a quantity that isn't a multiple of 30kg, it requires handling. (taking the cheese out of the fridge, cutting it up, weighing it, repackaging it to protect it). Technical design :

In your design, there is side bad pricing effect IMO. let's see :

bealdav commented 1 year ago

Hi @legalsylvain , thanks for your interest here and your deep analyze.

I asked for Carmen to develop a such module. Just some remarks:

customer order 101 Unit : Total = 100x8 + 1x10 = 810€. (Deconditionning is charged for 2€.)

About business, if you decide to sell product by unit, you should setup a methodology that allow to be efficient by unit. In your example, if you sell cheese, the efficient way is to have a full cheese to be dedicated to be cut then no need to go to the fridge each time a part. Then small extra price by unit could be good. If you sell cheese by quantities, the efficient way could be to manage in another place. Then discount, for low logistics costs is logic.

legalsylvain commented 1 year ago

the efficient way is to have a full cheese to be dedicated to be cut

Indeed, that's how it works.

then no need to go to the fridge each time a part.

Well. cheese must be stored in a refrigerator. this is the cold chain. So each time user prepare an order with a line "unpacked" he has to take the cheese out, cut it, protect it with celophane, and put it back in. That's unitary work.

If you sell cheese by quantities, the efficient way could be to manage in another place. Then discount, for low logistics costs is logic.

I don't get it sorry. For me, cutting cheese for 200 gram or 3 kg is the same extra work. if you apply discount, it doesn't pay this extra work. The same occures for your example with "pallet" I guess. could you precise what are kind of products are sold ? It could help me to understand.

carmenbianca commented 1 year ago

@legalsylvain I think the idea is, but correct me if I'm wrong, that Company A has a warehouse of pallets. The pallets all contain 100 boxes with paper (edit: for example!). It is cheaper/more efficient for the company to never 'split' a pallet, and just wheel off the entire pallet (or multiple pallets) to the customer.

The idea is that splitting the pallet and only selling a portion of the boxes of paper is additional labour that wouldn't need to happen if the entire pallet were sold.

legalsylvain commented 1 year ago

@legalsylvain I think the idea is, but correct me if I'm wrong, that Company A has a warehouse of pallets. The pallets all contain 100 boxes with paper (edit: for example!). It is cheaper/more efficient for the company to never 'split' a pallet, and just wheel off the entire pallet (or multiple pallets) to the customer.

The idea is that splitting the pallet and only selling a portion of the boxes of paper is additional labour that wouldn't need to happen if the entire pallet were sold.

I'm totally agree with your analysis. My question is more about percent discount vs fixed discount. (or percent surcharge vs fixed surcharge).

My opinion is that splitting pallet is the same work for 1 box of paper, or 10 boxes of paper.

grindtildeath commented 1 year ago

I'm not working that much on this topic anymore, but @jbaudoux 's take might be of more interest.

bealdav commented 1 year ago

Yes you're right here

My question is more about percent discount vs fixed discount. (or percent surcharge vs fixed surcharge).

not always here

My opinion is that splitting pallet is the same work for 1 box of paper, or 10 boxes of paper.

But you have plenty of pallets ready to go as it and only one pallet unbuilt to pick box of paper

I think there are 2 uses cases, then probably 2 different modules !?

percentage vs fix part

percentage seems to me easier to implements !?

What do you think ?

legalsylvain commented 1 year ago

percentage seems to me easier to implements !?

What do you think ?

No, I think that in the two cases there is a "create line process" that is the more complex thing. (can be manual (I think it's better), semi-automatic (done when confirming the sale.order) or automatic (done onchange, but I think it's quite hard to do and will not work if called via API, for exemple shopinvader, etc...) then :

So I think that some features should be common, and it could depend on settings. Not a clear point of view of the better implementation.

Maybe we can imagine a little call on that topic. What is the roadmap and the deadline ? I'm available during July.

bealdav commented 1 year ago

Yes good analyze. My use case is for shopinvader b2b In that case, I don't need this extra line because front user only has access to product_packaging_qty, not product_uom_qty, then he can order

1 pallet of 100 product if + 1 in the cart, then 200 products if - 1, 100 products

cc @sebastienbeau @hparfr

Probably that need require extra code compare to mine because of this extra line.

Maybe better in 2 modules ?

jbaudoux commented 1 year ago

Hello,

Here is my advice on the topic.

Never split a SO line for applying 2 different prices

Besides the complexity, this is, in my opinion, a bad idea as this does not integrate well in EDI exchanges & e-commerce connectors. So, if you really have to develop this, better do that in a separate additional module.

If I want the packaging price, I am responsible to order a multiple of a packaging. Otherwise, I get the unit price for the total quantity. Usually you want to favor selling by packaging, so no reason to apply a discount if you don't order a multiple of a packaging. And if you really need a package + some units, you can place 2 lines in the SO, each will have its correct price.

So if on your sales order line, you order the quantity of a pallet + 1 unit, you get the unit price for the total quantity. This should be the base behavior.

Use pricelist to manage prices

Define a new condition on a pricelist item by linking with what characterize your product packaging for ordering (box / secondary, pallet / tertiary). This is the purpose in v16 of the packaging level https://github.com/OCA/product-attribute/pull/1215

Don't use the new odoo packaging type, this is used to manage put-aways (a small box vs a large box, a EURO pallet vs a CHEP pallet, or a light vs a heavy pallet). You can have a lot of different package types for managing warehousing storage, while at ordering you just want to show secondary / tertiary. cf: https://www.gs1belu.org/en/packaging-information-0

This way, for a specific package level, you can give a formula or discount that applies to a category of product or to a specific product.

hparfr commented 1 year ago

In your case, you can implement it with differents products.

Sylvain' cheese can be implemented the same way: a "meule" of cheese is not a cut.

hparfr commented 1 year ago

Interesting link @jbaudoux thanks

bealdav commented 1 year ago

Thanks a lot for your feedbacks

bealdav commented 1 year ago

I'm Ok to stick on pricelist to manage quantity price, I think it's cautious

Then quantity is defined in 2 places :

Probably these 2 fields should match in most cases. If not, you may risk to define a package of 25 and set a price of 26, then package in sale line could get price with 1 instead of 26.

Probably that this risk is shared by all projects using packages.

How to deal with that ?

  1. only watch/check groundless difference between these quantity
  2. alert when pricelist item is modified without matching with packaging qty
  3. prevent to have no match

I think these 3 features are ~ generic.

In my case I tend to think to implements feature 1 and 2.

Do you think it's generic or is there other options ?

Thanks for your feedback