Skip to content
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

[16.0] [IMP] Make packaging required on orders for configured products. #3528

Draft
wants to merge 2 commits into
base: 16.0
Choose a base branch
from

Conversation

edlopen
Copy link
Member

@edlopen edlopen commented Jan 9, 2025

This PR allows a configured product not to be allowed to be sold without packaging.

This video explains the improvement
https://www.loom.com/share/b4b6a6fc9cdb406086115195a1eeb1c4

@moduon: MT-8489

@OCA-git-bot
Copy link
Contributor

Hi @yajo, @rafaelbn,
some modules you are maintaining are being modified, check this out!

Copy link
Member

@yajo yajo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is close, but I added a lot of implementation details to help for making it more maintainable and usable.

Thanks!

Comment on lines +120 to +121
@api.depends("product_id", "product_uom_qty", "product_uom")
def _warning_product_packaging_required(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a constraint instead:

Suggested change
@api.depends("product_id", "product_uom_qty", "product_uom")
def _warning_product_packaging_required(self):
@api.constrains("product_id", "product_packaging_id")
def _check_product_packaging_required(self):

result = {}
for line in self:
if line.require_packaging and not line.product_packaging_id:
raise UserError(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: within constrains, you should raise ValidationErrors:

Suggested change
raise UserError(
raise ValidationError(

Comment on lines +128 to +129
"The product %s requires a packaging to be sold"
% line.product_id.name
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: you must render the message before composing it for translations to work fine:

Suggested change
"The product %s requires a packaging to be sold"
% line.product_id.name
"The product %s requires a packaging to be sold",
line.product_id.name

@api.depends("product_id", "product_uom_qty", "product_uom")
def _warning_product_packaging_required(self):
"""Notify the user when a packaging is required."""
result = {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: no need for a result while constraining.

Suggested change
result = {}

% line.product_id.name
)
)
return result
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

continuing from above...

Suggested change
return result

Comment on lines +49 to 66
res = line._warning_product_packaging_required()
if res:
return res
return result

@api.depends("product_id", "product_uom_qty", "product_uom")
def _warning_product_packaging_required(self):
"""Notify the user when a packaging is required."""
result = {}
for line in self:
if line.require_packaging and not line.product_packaging_id:
raise UserError(
_(
"The product %s requires a packaging to be sold"
% line.product_id.name
)
)
return result
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: use a constrain instead, and I summarize all the comments from above here too:

Suggested change
res = line._warning_product_packaging_required()
if res:
return res
return result
@api.depends("product_id", "product_uom_qty", "product_uom")
def _warning_product_packaging_required(self):
"""Notify the user when a packaging is required."""
result = {}
for line in self:
if line.require_packaging and not line.product_packaging_id:
raise UserError(
_(
"The product %s requires a packaging to be sold"
% line.product_id.name
)
)
return result
@api.constrains("product_id", "product_packaging_id")
def _check_product_packaging_required(self):
"""Notify the user when a packaging is required."""
for line in self:
if line.require_packaging and not line.product_packaging_id:
raise ValidationError(
_(
"The product %s requires a packaging to be sold",
line.product_id.name
)
)

<group string="Packaging Division">
<field
name="require_packaging"
placeholder="Indicates if the product can be sold individually or if it requires keeping the original packaging."
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: a placeholder doesn't make sense if the input is a checkbox. I already commented above about adding help to the field, so this is unnecessary.

Suggested change
placeholder="Indicates if the product can be sold individually or if it requires keeping the original packaging."

<field name="inherit_id" ref="product.product_template_form_view" />
<field name="arch" type="xml">
<xpath expr="//page[@name='inventory']" position="inside">
<group string="Packaging Division">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: since you're creating a new group, it can land far away from the packaging configuration. Better, put the new checkbox within the same visual group as the rest of packaging configuration:

image

Comment on lines +57 to +65
<!-- Make packaging qty readonly when the product is not allow to divide the packaging -->
<xpath
expr="//field[@name='order_line']/tree/field[@name='product_packaging_qty']"
position="attributes"
>
<attribute
name="attrs"
>{'readonly': [('require_packaging', '=', True)]}</attribute>
</xpath>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: so, we require packaging, but we don't allow to set how many? It doesn't make sense:
image

Instead, please do the opposite thing. The field that you should make readonly is product_uom_qty. That way, the user is not allowed to break the packaging. They're only allowed to increase or decrease whole packaging sets.

Comment on lines 49 to 54
<field
name="product_packaging_qty"
groups="product.group_stock_packaging"
widget="numeric_step"
attrs="{'readonly': [('product_packaging_id', '=', False)]}"
attrs="{'readonly': ['|', ('product_packaging_id', '=', False), ('require_packaging', '=', True)]}"
/>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: just like below, this field should be writable always when there's a packaging. But instead, do the opposite and make the product_uom_qty field readonly when require_packaging == True.

@yajo yajo marked this pull request as draft January 13, 2025 12:02
@Shide
Copy link
Contributor

Shide commented Jan 14, 2025

I think the best approach will be using the same workflow as Odoo does:

On product.category

Add a selection field as packaging_reserve_method called packaging_sell_method with 2 options:

  • full: Sell only full packagings
  • partial: Sell partial packagings

The workflow will be the same as the packaging_reserve_method field, but checking packagings when selling products.

@yajo
Copy link
Member

yajo commented Jan 14, 2025 via email

@pedrobaeza
Copy link
Member

FYI, this change in 19.0 will totally impact you: odoo/odoo#184131

@Shide
Copy link
Contributor

Shide commented Jan 14, 2025

Since those fields exist already, would it make more sense to reuse them, instead of creating new ones?

Message ID: @.***>

Could be interesting to force commercial users to sell entire packages, but maybe in certain cases allow to send partial packages...

Copy link
Member

@mmequignon mmequignon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have something similar in v14.0 https://github.com/OCA/sale-workflow/tree/14.0/sale_by_packaging
I would migrate it to 16.0 instead.

@rafaelbn rafaelbn added this to the 16.0 milestone Jan 19, 2025
@rafaelbn
Copy link
Member

Hello @mmequignon ,

Thank you so much for your feedback and for pointing us to the sale_by_packaging module. We’re already familiar with it, but we believe it addresses a different use case. 😄

The main difference lies in flexibility. Your module revolves around strictly selling by packaging, while our use case is much more dynamic and flexible. 🚀

Here’s what we mean:

  • Sometimes we sell by packaging, and sometimes we don’t.
  • In some scenarios, packaging is used optionally, allowing for different combinations.

For our clients, this flexibility is critical, and unfortunately, the sale_by_packaging module doesn’t meet their needs.

Additionally, we’ve noticed that your module introduces extra complexity and dependencies that are unnecessary for our use case, such as:

  • sale_order_line_packaging_qty
  • product_packaging_type

If we’re mistaken here, we’d love to see more clarity! 🙏 When migrating the module, it would be super helpful if you could improve the README and even record a short video 🖥️🎥 explaining how to handle these use cases:

  1. Products without packaging: Ensure packaging is not required.
  2. No forced packaging type: Allow products with packaging but without enforcing a type (not needed for us).
  3. Optional packaging: Products with packaging (no type) that can be sold either with or without packaging.
  4. Conditional enforcement: Products with packaging (no type) where selling by packaging is only enforced in specific cases.

If your module already covers all these scenarios, we’d be delighted to reconsider it! 😊💡

Thanks again for your input, and let us know your thoughts!

Best regards,
Rafael ❤️

@rafaelbn rafaelbn requested a review from mmequignon January 19, 2025 12:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants