-
-
Notifications
You must be signed in to change notification settings - Fork 671
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8c24218
commit 8265865
Showing
14 changed files
with
288 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import models |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Copyright 2023 Camptocamp SA | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) | ||
|
||
{ | ||
"name": "MTO Route Product Variant", | ||
"summary": "Allow to individually set variants as MTO", | ||
"version": "14.0.1.0.0", | ||
"development_status": "Alpha", | ||
"category": "Inventory", | ||
"website": "https://github.com/OCA/stock-workflow", | ||
"author": "Camptocamp SA, Odoo Community Association (OCA)", | ||
"maintainers": ["mmequignon"], | ||
"license": "AGPL-3", | ||
"installable": True, | ||
"auto_install": False, | ||
"depends": ["stock"], | ||
"data": ["views/product_product.xml"], | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from . import product_product | ||
from . import product_template |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
# Copyright 2023 Camptocamp SA | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) | ||
|
||
from odoo import api, models, fields | ||
|
||
IS_MTO_HELP = """ | ||
Check or Uncheck this field if you want this variant to have another | ||
mto configration than its template. | ||
""" | ||
|
||
class ProductProduct(models.Model): | ||
_inherit = "product.product" | ||
|
||
is_mto = fields.Boolean( | ||
string="Variant is Mto", | ||
compute="_compute_is_mto", | ||
inverse="_inverse_is_mto", | ||
store="true", | ||
help=IS_MTO_HELP, | ||
index=True | ||
) | ||
|
||
@api.depends("product_tmpl_id.route_ids") | ||
def _compute_is_mto(self): | ||
# We only want to force all variants `is_mto` to True when | ||
# the mto route is explicitely set on its template. | ||
# Watching the mto route is not enough, since we might | ||
# have a template with the mto route, and disabled the mto route | ||
# for a few of its variants | ||
# If a user sets another route on the variant, we do not want the | ||
# mto disabled variants to be updated. | ||
# To ensure that, the created `has_mto_route_changed` boolean field | ||
# is set to True only when the MTO route is set on a template. | ||
mto_route = self.env.ref("stock.route_warehouse0_mto") | ||
templates = self.product_tmpl_id | ||
# Only variants with a template with the MTO route and has_mto_route_changed | ||
# should be updated. | ||
mto_templates = templates.filtered( | ||
lambda t: mto_route in t.route_ids and t.has_mto_route_changed | ||
) | ||
mto_variants = self.filtered(lambda p: p.product_tmpl_id in mto_templates) | ||
mto_variants.is_mto = True | ||
# For the other variants, keep their current value. | ||
other_variants = self - mto_variants | ||
for variant in other_variants: | ||
variant.is_mto = variant.is_mto | ||
# Then set template's has_mto_route_changed to False, as it | ||
# has been handled above | ||
templates.has_mto_route_changed = False | ||
|
||
def _inverse_is_mto(self): | ||
# When all variants of a template are `is_mto == False`, drop the MTO route | ||
# from the template, otherwise do nothing | ||
mto_route = self.env.ref("stock.route_warehouse0_mto") | ||
for template in self.product_tmpl_id: | ||
is_mto = False | ||
for variant in template.product_variant_ids: | ||
if variant.is_mto: | ||
is_mto = True | ||
break | ||
# If no variant is mto, then drop the route of the template. | ||
if not is_mto: | ||
template.route_ids = [(3, mto_route.id, 0)] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Copyright 2023 Camptocamp SA | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) | ||
|
||
from odoo import models, fields | ||
|
||
class ProductTemplate(models.Model): | ||
_inherit = "product.template" | ||
|
||
has_mto_route_changed = fields.Boolean() | ||
|
||
def write(self, values): | ||
if not "route_ids" in values: | ||
return super().write(values) | ||
# This route_ids change will trigger variant's _compute_is_mto. | ||
# We want to set variant's is_mto to True only if their | ||
# template has been set to True here ↓ | ||
mto_route = self.env.ref("stock.route_warehouse0_mto") | ||
template_not_mto_before = self.filtered(lambda t: mto_route not in t.route_ids) | ||
res = super().write(values) | ||
template_mto_after = self.filtered(lambda t: mto_route in t.route_ids) | ||
# Templates where mto route has changed are those where | ||
# the mto route has been set | ||
templates_mto_set = template_not_mto_before & template_mto_after | ||
templates_mto_set.has_mto_route_changed = True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
* Matthieu Méquignon <[email protected]> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Allow to individually set variants as MTO |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
This module is useless on its own. | ||
|
||
However, it is meant to give the ability to check if a product variant is MTO, | ||
rather than checking its template's routes. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import test_mto_variant |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# Copyright 2023 Camptocamp SA | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) | ||
|
||
from odoo.tests.common import Form, SavepointCase | ||
|
||
|
||
class TestMTOVariantCommon(SavepointCase): | ||
at_install = False | ||
post_install = True | ||
|
||
@classmethod | ||
def setUpClass(cls): | ||
super().setUpClass() | ||
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) | ||
cls.setUpClassProduct() | ||
|
||
|
||
@classmethod | ||
def setUpClassProduct(cls): | ||
cls.color = cls.env['product.attribute'].create({'name': 'Color'}) | ||
value_model = cls.env['product.attribute.value'] | ||
cls.values = value_model.create( | ||
[ | ||
{'name': 'red', 'attribute_id': cls.color.id}, | ||
{'name': 'blue', 'attribute_id': cls.color.id}, | ||
{'name': 'black', 'attribute_id': cls.color.id}, | ||
{'name': 'green', 'attribute_id': cls.color.id}, | ||
] | ||
) | ||
cls.value_red = cls.values.filtered(lambda v: v.name == "red") | ||
cls.value_blue = cls.values.filtered(lambda v: v.name == "blue") | ||
cls.value_black = cls.values.filtered(lambda v: v.name == "black") | ||
cls.value_green = cls.values.filtered(lambda v: v.name == "green") | ||
cls.template_pen = cls.env["product.template"].create( | ||
{ | ||
"name": "pen", | ||
'attribute_line_ids': [ | ||
(0, 0, { | ||
'attribute_id': cls.color.id, | ||
'value_ids': [(6, 0, cls.values.ids)], | ||
}) | ||
] | ||
} | ||
) | ||
cls.variants_pen = cls.template_pen.product_variant_ids | ||
cls.black_pen = cls.variants_pen.filtered(lambda v: v.product_template_attribute_value_ids.name == "black") | ||
cls.green_pen = cls.variants_pen.filtered(lambda v: v.product_template_attribute_value_ids.name == "green") | ||
cls.red_pen = cls.variants_pen.filtered(lambda v: v.product_template_attribute_value_ids.name == "red") | ||
cls.blue_pen = cls.variants_pen.filtered(lambda v: v.product_template_attribute_value_ids.name == "blue") | ||
cls.mto_route = cls.env.ref("stock.route_warehouse0_mto") | ||
cls.mto_route.active = True | ||
|
||
def add_route(self, template, route): | ||
if not route: | ||
route = self.mto_route | ||
with Form(template) as record: | ||
record.route_ids.add(route) | ||
|
||
def remove_route(self, template, route): | ||
if not route: | ||
route = self.mto_route | ||
with Form(template) as record: | ||
record.route_ids.remove(id=route.id) | ||
|
||
@classmethod | ||
def toggle_is_mto(self, records): | ||
for record in records: | ||
record.is_mto = not record.is_mto | ||
|
||
def assertVariantsMTO(self, records): | ||
records.invalidate_cache(["is_mto"]) | ||
self.assertTrue(all([record.is_mto for record in records])) | ||
|
||
def assertVariantsNotMTO(self, records): | ||
records.invalidate_cache(["is_mto"]) | ||
self.assertFalse(any([record.is_mto for record in records])) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
# Copyright 2023 Camptocamp SA | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) | ||
|
||
from .common import TestMTOVariantCommon | ||
|
||
|
||
class TestMTOVariant(TestMTOVariantCommon): | ||
|
||
def test_variants_mto(self): | ||
# instanciate variables | ||
pen_template = self.template_pen | ||
pens = self.variants_pen | ||
blue_pen = self.blue_pen | ||
red_pen = self.red_pen | ||
green_pen = self.green_pen | ||
black_pen = self.black_pen | ||
self.assertVariantsNotMTO(pens) | ||
# enable mto route for black pen | ||
self.toggle_is_mto(black_pen) | ||
self.assertVariantsMTO(black_pen) | ||
self.assertVariantsNotMTO(blue_pen | green_pen | red_pen) | ||
# enable mto route for black and blue pens | ||
self.toggle_is_mto(blue_pen) | ||
self.assertVariantsMTO(black_pen | blue_pen) | ||
self.assertVariantsNotMTO(red_pen | green_pen) | ||
# Now enable the mto route for the template, all variants get is_mto = True | ||
self.add_route(pen_template, self.mto_route) | ||
self.assertVariantsMTO(pens) | ||
# Disable mto route for black_pen | ||
self.toggle_is_mto(black_pen) | ||
self.assertVariantsNotMTO(black_pen) | ||
self.assertVariantsMTO(blue_pen | green_pen | red_pen) | ||
# Disable mto route on the template, variants is_mto is kept | ||
self.remove_route(pen_template, self.mto_route) | ||
# is_mto is unchanged | ||
self.assertVariantsNotMTO(black_pen) | ||
self.assertVariantsMTO(blue_pen | green_pen | red_pen) | ||
|
||
def test_template_routes_updated(self): | ||
# instanciate variables | ||
pen_template = self.template_pen | ||
pens = self.variants_pen | ||
blue_pen = self.blue_pen | ||
red_pen = self.red_pen | ||
green_pen = self.green_pen | ||
black_pen = self.black_pen | ||
self.assertVariantsNotMTO(pens) | ||
# If template is set to MTO, all variants are updated | ||
self.add_route(pen_template, self.mto_route) | ||
self.assertVariantsMTO(pens) | ||
# Now toggle a few variants to is_mto == False | ||
self.toggle_is_mto(black_pen | blue_pen) | ||
self.assertVariantsMTO(green_pen | red_pen) | ||
self.assertVariantsNotMTO(black_pen | blue_pen) | ||
# Now modifying template.route_ids to trigger variant's _compute_is_mto | ||
random_route = self.mto_route.create({"name": "loutourout de la vit"}) | ||
self.add_route(pen_template, random_route) | ||
# Template is still MTO, but variants is_mto shouldn't have changed | ||
self.assertVariantsMTO(green_pen | red_pen) | ||
self.assertVariantsNotMTO(black_pen | blue_pen) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<!-- Copyright 2023 Camptocamp SA | ||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). --> | ||
<odoo> | ||
|
||
<record id="product_normal_form_view" model="ir.ui.view"> | ||
<field name="name">product.product.form.inherit</field> | ||
<field name="model">product.product</field> | ||
<field name="inherit_id" ref="product.product_normal_form_view"/> | ||
<field name="arch" type="xml"> | ||
<group name="operations" position="inside"> | ||
<field name="is_mto"/> | ||
</group> | ||
</field> | ||
</record> | ||
|
||
<record id="product_variant_easy_edit_view" model="ir.ui.view"> | ||
<field name="name">product.product.form.easy.inherit</field> | ||
<field name="model">product.product</field> | ||
<field name="inherit_id" ref="product.product_variant_easy_edit_view"/> | ||
<field name="arch" type="xml"> | ||
<group name="weight" position="inside"> | ||
<field name="is_mto"/> | ||
</group> | ||
</field> | ||
</record> | ||
|
||
|
||
|
||
</odoo> |
1 change: 1 addition & 0 deletions
1
setup/mto_route_product_variant/odoo/addons/mto_route_product_variant
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../../../mto_route_product_variant |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import setuptools | ||
|
||
setuptools.setup( | ||
setup_requires=['setuptools-odoo'], | ||
odoo_addon=True, | ||
) |