diff --git a/sale_elaboration/README.rst b/sale_elaboration/README.rst index 70b3b0bd1a6..d392e715b08 100644 --- a/sale_elaboration/README.rst +++ b/sale_elaboration/README.rst @@ -1,7 +1,3 @@ -.. image:: https://odoo-community.org/readme-banner-image - :target: https://odoo-community.org/get-involved?utm_source=readme - :alt: Odoo Community Association - ================ Sale Elaboration ================ @@ -17,7 +13,7 @@ Sale Elaboration .. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png :target: https://odoo-community.org/page/development-status :alt: Production/Stable -.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fsale--workflow-lightgray.png?logo=github @@ -75,6 +71,15 @@ To configure this module you need to: You can define elaboration profiles to limit the elaborations that can be selected for each product. +To set the profile globally for a product category: + +1. Go to *Inventory > Configuration > Product Categories* and choose + one. +2. In the **Logistics** sections, you can set the desired **Elaboration + profile**. + +If you want to set an specific elaboration profile for a product: + 1. Go to *Sale > Configuration > Elaborations > Sale Elaboration Profile*. 2. Create a new record. diff --git a/sale_elaboration/__manifest__.py b/sale_elaboration/__manifest__.py index 105b33578a1..e7783409489 100644 --- a/sale_elaboration/__manifest__.py +++ b/sale_elaboration/__manifest__.py @@ -26,6 +26,7 @@ "reports/report_base.xml", "reports/report_deliveryslip.xml", "reports/report_picking_operations.xml", + "views/product_category_views.xml", ], "demo": ["demo/sale_elaboration_demo.xml"], "pre_init_hook": "pre_init_hook", diff --git a/sale_elaboration/models/__init__.py b/sale_elaboration/models/__init__.py index cd54a345a2c..8e65b7348df 100644 --- a/sale_elaboration/models/__init__.py +++ b/sale_elaboration/models/__init__.py @@ -1,5 +1,6 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from . import product +from . import product_category from . import product_elaboration from . import product_elaboration_mixin from . import product_elaboration_profile diff --git a/sale_elaboration/models/product.py b/sale_elaboration/models/product.py index c83cde98370..e98ec5d535c 100644 --- a/sale_elaboration/models/product.py +++ b/sale_elaboration/models/product.py @@ -7,5 +7,8 @@ class ProductProduct(models.Model): _inherit = "product.product" elaboration_profile_id = fields.Many2one( - comodel_name="product.elaboration.profile", ondelete="restrict" + comodel_name="product.elaboration.profile", + ondelete="restrict", + help="Keep this field empty to use the default value from the product " + "category.", ) diff --git a/sale_elaboration/models/product_category.py b/sale_elaboration/models/product_category.py new file mode 100644 index 00000000000..04d6548c8d0 --- /dev/null +++ b/sale_elaboration/models/product_category.py @@ -0,0 +1,11 @@ +# Copyright 2025 Moduon Team S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import fields, models + + +class ProductCategory(models.Model): + _inherit = "product.category" + + elaboration_profile_id = fields.Many2one( + comodel_name="product.elaboration.profile", string="Elaboration Profile" + ) diff --git a/sale_elaboration/models/product_template.py b/sale_elaboration/models/product_template.py index fe2766ee130..1442cd4b7ca 100644 --- a/sale_elaboration/models/product_template.py +++ b/sale_elaboration/models/product_template.py @@ -12,6 +12,8 @@ class ProductTemplate(models.Model): compute="_compute_elaboration_profile_id", inverse="_inverse_elaboration_profile_id", store=True, + help="Keep this field empty to use the default value from the product " + "category.", ) @api.depends("product_variant_ids", "product_variant_ids.elaboration_profile_id") diff --git a/sale_elaboration/models/sale_order.py b/sale_elaboration/models/sale_order.py index 33e0fdd4e4f..ffbfb38b842 100644 --- a/sale_elaboration/models/sale_order.py +++ b/sale_elaboration/models/sale_order.py @@ -48,7 +48,8 @@ class SaleOrderLine(models.Model): date_order = fields.Datetime(related="order_id.date_order", string="Date") route_id = fields.Many2one(compute="_compute_route_id", store=True, readonly=False) elaboration_profile_id = fields.Many2one( - related="product_id.elaboration_profile_id" + comodel_name="product.elaboration.profile", + compute="_compute_elaboration_profile_id", ) elaboration_price_unit = fields.Float( "Elab. Price", compute="_compute_elaboration_price_unit", store=True @@ -59,6 +60,16 @@ class SaleOrderLine(models.Model): help=("Dummy field to be able to find prepared lines"), ) + @api.depends("product_id") + def _compute_elaboration_profile_id(self): + """Order of applicability: product profile > category profile > no profile""" + self.elaboration_profile_id = False + for line in self.filtered("product_id"): + line.elaboration_profile_id = ( + line.product_id.elaboration_profile_id + or line.product_id.categ_id.elaboration_profile_id + ) + def get_elaboration_stock_route(self): self.ensure_one() return self.elaboration_ids.route_ids[:1] diff --git a/sale_elaboration/readme/CONFIGURE.md b/sale_elaboration/readme/CONFIGURE.md index 923f1334125..4301e1da506 100644 --- a/sale_elaboration/readme/CONFIGURE.md +++ b/sale_elaboration/readme/CONFIGURE.md @@ -14,6 +14,13 @@ To configure this module you need to: You can define elaboration profiles to limit the elaborations that can be selected for each product. +To set the profile globally for a product category: + +1. Go to *Inventory > Configuration > Product Categories* and choose one. +2. In the **Logistics** sections, you can set the desired **Elaboration profile**. + +If you want to set an specific elaboration profile for a product: + 1. Go to *Sale \> Configuration \> Elaborations \> Sale Elaboration Profile*. 2. Create a new record. 3. Select the elaborations included to the profile. diff --git a/sale_elaboration/static/description/index.html b/sale_elaboration/static/description/index.html index e431f1421ee..521f9646c83 100644 --- a/sale_elaboration/static/description/index.html +++ b/sale_elaboration/static/description/index.html @@ -3,7 +3,7 @@ -README.rst +Sale Elaboration -
+
+

Sale Elaboration

- - -Odoo Community Association - -
-

Sale Elaboration

-

Production/Stable License: AGPL-3 OCA/sale-workflow Translate me on Weblate Try me on Runboat

+

Production/Stable License: AGPL-3 OCA/sale-workflow Translate me on Weblate Try me on Runboat

This module extends the functionality of sales orders to allow to set an elaboration on lines that will add an extra order line with an elaboration product linked to it when the delivery order is validated.

@@ -401,13 +396,13 @@

Sale Elaboration

-

Use Cases / Context

+

Use Cases / Context

This module was created to meet the need of providing the customer with products that are not transformed into something new, but rather require a simple preparation process. Example: Scaling a fish

-

Configuration

+

Configuration

To configure this module you need to:

  1. Go to Sale > Configuration > Elaborations > Sale Elaboration.
  2. @@ -422,6 +417,14 @@

    Configuration

You can define elaboration profiles to limit the elaborations that can be selected for each product.

+

To set the profile globally for a product category:

+
    +
  1. Go to Inventory > Configuration > Product Categories and choose +one.
  2. +
  3. In the Logistics sections, you can set the desired Elaboration +profile.
  4. +
+

If you want to set an specific elaboration profile for a product:

  1. Go to Sale > Configuration > Elaborations > Sale Elaboration Profile.
  2. @@ -431,7 +434,7 @@

    Configuration

-

Usage

+

Usage

  1. Go to Sale > Quotations.
  2. Create a sales order.
  3. @@ -447,7 +450,7 @@

    Usage

-

Bug Tracker

+

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed @@ -455,15 +458,15 @@

Bug Tracker

Do not contact contributors directly about support or help with technical issues.

-

Credits

+

Credits

-

Authors

+

Authors

  • Tecnativa
-

Contributors

+

Contributors

-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association @@ -492,6 +495,5 @@

Maintainers

-
diff --git a/sale_elaboration/tests/test_sale_elaboration.py b/sale_elaboration/tests/test_sale_elaboration.py index e726a14bd2a..db9fb19d70e 100644 --- a/sale_elaboration/tests/test_sale_elaboration.py +++ b/sale_elaboration/tests/test_sale_elaboration.py @@ -1,5 +1,6 @@ # Copyright 2018 Tecnativa - Sergio Teruel # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import Command from odoo.tests import Form, tagged from odoo.addons.account.tests.common import AccountTestInvoicingCommon @@ -11,9 +12,21 @@ class TestSaleElaboration(AccountTestInvoicingCommon): def setUpClass(cls): super().setUpClass() cls.Elaboration = cls.env["product.elaboration"] + cls.ElaborationProfile = cls.env["product.elaboration.profile"] + cls.category_1 = cls.env["product.category"].create({"name": "Meat"}) + cls.category_2 = cls.env["product.category"].create({"name": "Fish"}) cls.product = cls.env["product.product"].create( {"name": "test", "tracking": "none", "list_price": 1000} ) + cls.product_2 = cls.env["product.product"].create( + {"name": "test 2", "tracking": "none", "list_price": 1000} + ) + cls.product_3 = cls.env["product.product"].create( + {"name": "test 2", "tracking": "none", "list_price": 1000} + ) + cls.product.categ_id = cls.category_1 + cls.product_2.categ_id = cls.category_2 + cls.product_3.categ_id = cls.category_1 cls.product_elaboration_A = cls.env["product.product"].create( { "name": "Product Elaboration A", @@ -65,9 +78,25 @@ def setUpClass(cls): "product_id": cls.product_elaboration_B.id, } ) + cls.elaboration_profile_a = cls.ElaborationProfile.create( + { + "name": "Elaboration Profile A", + "elaboration_ids": [ + Command.set([cls.elaboration_a.id, cls.elaboration_b.id]) + ], + } + ) + cls.elaboration_profile_b = cls.ElaborationProfile.create( + { + "name": "Elaboration Profile B", + "elaboration_ids": [Command.set(cls.elaboration_a.ids)], + } + ) + cls.product.elaboration_profile_id = cls.elaboration_profile_a cls.order = cls._create_sale_order( cls, [(cls.product, 10, [cls.elaboration_a])] ) + cls.category_1.elaboration_profile_id = cls.elaboration_profile_b def _create_sale_order(self, products_info): order_form = Form(self.env["sale.order"]) diff --git a/sale_elaboration/views/product_category_views.xml b/sale_elaboration/views/product_category_views.xml new file mode 100644 index 00000000000..7ab3a80c9c7 --- /dev/null +++ b/sale_elaboration/views/product_category_views.xml @@ -0,0 +1,16 @@ + + + + product.category.view.form.sale.elaboration + product.category + + + + + + + +