Skip to content

Commit 4889262

Browse files
committed
[MIG] stock_product_variant_mto: Migration to 18.0
1 parent bee6c75 commit 4889262

File tree

9 files changed

+115
-65
lines changed

9 files changed

+115
-65
lines changed

stock_product_variant_mto/README.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,15 @@ Contributors
6464

6565
- Matthieu Méquignon <[email protected]>
6666
- Akim Juillerat <[email protected]>
67+
- Chau Le <[email protected]>
68+
69+
Other credits
70+
-------------
71+
72+
The development and migration of this module has been financially
73+
supported by:
74+
75+
- Camptocamp
6776

6877
Maintainers
6978
-----------

stock_product_variant_mto/__manifest__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
{
55
"name": "Stock Product Variant MTO",
66
"summary": "Allow to individually set variants as MTO",
7-
"version": "14.0.1.0.0",
7+
"version": "18.0.1.0.0",
88
"development_status": "Alpha",
99
"category": "Inventory",
1010
"website": "https://github.com/OCA/stock-logistics-workflow",

stock_product_variant_mto/models/product_product.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,30 +23,31 @@ class ProductProduct(models.Model):
2323
)
2424

2525
route_ids = fields.Many2many(
26-
"stock.location.route",
26+
"stock.route",
2727
compute="_compute_route_ids",
2828
domain="[('product_selectable', '=', True)]",
29-
store=False,
29+
store=True
3030
)
3131

3232
def _compute_is_mto(self):
3333
mto_route = self.env.ref("stock.route_warehouse0_mto", raise_if_not_found=False)
34+
if not mto_route:
35+
self.update({"is_mto": False})
36+
return
37+
3438
for product in self:
35-
if not mto_route:
36-
product.is_mto = False
37-
continue
3839
product.is_mto = mto_route in product.product_tmpl_id.route_ids
3940

4041
@api.depends("is_mto", "product_tmpl_id.route_ids")
4142
def _compute_route_ids(self):
4243
mto_route = self.env.ref("stock.route_warehouse0_mto", raise_if_not_found=False)
4344
for product in self:
44-
if mto_route and mto_route in product.product_tmpl_id.route_ids:
45-
if not product.is_mto:
46-
product.route_ids = product.product_tmpl_id.route_ids - mto_route
47-
continue
48-
else:
49-
if mto_route and product.is_mto:
50-
product.route_ids = product.product_tmpl_id.route_ids + mto_route
51-
continue
52-
product.route_ids = product.product_tmpl_id.route_ids
45+
new_route_ids = product.product_tmpl_id.route_ids
46+
47+
if mto_route:
48+
if product.is_mto and mto_route not in new_route_ids:
49+
new_route_ids += mto_route
50+
elif not product.is_mto and mto_route in new_route_ids:
51+
new_route_ids -= mto_route
52+
53+
product.route_ids = new_route_ids
Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,72 @@
11
# Copyright 2023 Camptocamp SA
22
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
33

4-
from odoo import _, api, models
4+
from odoo import api, models
55

66

77
class ProductTemplate(models.Model):
88
_inherit = "product.template"
99

1010
def write(self, values):
11-
if "route_ids" not in values:
11+
mto_route = self.env.ref("stock.route_warehouse0_mto", raise_if_not_found=False)
12+
13+
if "route_ids" not in values or not mto_route:
1214
return super().write(values)
15+
1316
# As _compute_is_mto cannot use api.depends (or it would reset MTO
1417
# route on variants as soon as there is a change on the template routes),
1518
# we need to check which template in self had MTO route activated
1619
# or deactivated to force the recomputation of is_mto on variants
17-
mto_route = self.env.ref("stock.route_warehouse0_mto")
18-
template_not_mto_before = self.filtered(lambda t: mto_route not in t.route_ids)
20+
21+
templates_not_mto_before = self.filtered(lambda t: mto_route not in t.route_ids)
22+
1923
res = super().write(values)
24+
2025
templates_mto_after = self.filtered(lambda t: mto_route in t.route_ids)
21-
templates_mto_added = template_not_mto_before & templates_mto_after
22-
templates_mto_removed = (self - template_not_mto_before) & (
23-
self - templates_mto_after
24-
)
25-
(
26+
templates_mto_added = templates_not_mto_before & templates_mto_after
27+
templates_mto_removed = self - templates_mto_after - templates_not_mto_before
28+
29+
affected_product_variants = (
2630
templates_mto_added | templates_mto_removed
27-
).product_variant_ids._compute_is_mto()
31+
).product_variant_ids
32+
if affected_product_variants:
33+
affected_product_variants._compute_is_mto()
34+
2835
return res
2936

3037
@api.onchange("route_ids")
3138
def onchange_route_ids(self):
3239
mto_route = self.env.ref("stock.route_warehouse0_mto", raise_if_not_found=False)
33-
if (
34-
mto_route not in self._origin.route_ids
35-
and mto_route in self.route_ids._origin
36-
):
40+
if not mto_route:
41+
return
42+
43+
origin_routes = (
44+
self._origin.route_ids if self._origin else self.env["stock.route"]
45+
)
46+
current_routes = (
47+
self.route_ids._origin if self.route_ids else self.env["stock.route"]
48+
)
49+
50+
if mto_route not in origin_routes and mto_route in current_routes:
3751
# Return warning activating MTO route
3852
return {
3953
"warning": {
40-
"title": _("Warning"),
41-
"message": _(
42-
"Activating MTO route will reset `Variant is MTO` setting on the variants."
54+
"title": self.env._("Warning"),
55+
"message": self.env._(
56+
"Activating MTO route will reset `Variant is MTO` "
57+
"setting on the variants."
4358
),
4459
}
4560
}
46-
if (
47-
mto_route in self._origin.route_ids
48-
and mto_route not in self.route_ids._origin
49-
):
61+
62+
if mto_route in origin_routes and mto_route not in current_routes:
5063
# Return warning deactivating MTO route
5164
return {
5265
"warning": {
53-
"title": _("Warning"),
54-
"message": _(
55-
"Deactivating MTO route will reset `Variant is MTO` setting on the variants."
66+
"title": self.env._("Warning"),
67+
"message": self.env._(
68+
"Deactivating MTO route will reset `Variant is MTO` "
69+
"setting on the variants."
5670
),
5771
}
5872
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
- Matthieu Méquignon \<<[email protected]>\>
22
- Akim Juillerat \<<[email protected]>\>
3+
- Chau Le \<<[email protected]>\>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
The development and migration of this module has been financially supported by:
2+
3+
- Camptocamp

stock_product_variant_mto/static/description/index.html

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,8 @@ <h1 class="title">Stock Product Variant MTO</h1>
385385
<li><a class="reference internal" href="#credits" id="toc-entry-2">Credits</a><ul>
386386
<li><a class="reference internal" href="#authors" id="toc-entry-3">Authors</a></li>
387387
<li><a class="reference internal" href="#contributors" id="toc-entry-4">Contributors</a></li>
388-
<li><a class="reference internal" href="#maintainers" id="toc-entry-5">Maintainers</a></li>
388+
<li><a class="reference internal" href="#other-credits" id="toc-entry-5">Other credits</a></li>
389+
<li><a class="reference internal" href="#maintainers" id="toc-entry-6">Maintainers</a></li>
389390
</ul>
390391
</li>
391392
</ul>
@@ -411,10 +412,19 @@ <h2><a class="toc-backref" href="#toc-entry-4">Contributors</a></h2>
411412
<ul class="simple">
412413
<li>Matthieu Méquignon &lt;<a class="reference external" href="mailto:matthieu.mequignon&#64;camptocamp.com">matthieu.mequignon&#64;camptocamp.com</a>&gt;</li>
413414
<li>Akim Juillerat &lt;<a class="reference external" href="mailto:akim.juillerat&#64;camptocamp.com">akim.juillerat&#64;camptocamp.com</a>&gt;</li>
415+
<li>Chau Le &lt;<a class="reference external" href="mailto:chaulb&#64;trobz.com">chaulb&#64;trobz.com</a>&gt;</li>
416+
</ul>
417+
</div>
418+
<div class="section" id="other-credits">
419+
<h2><a class="toc-backref" href="#toc-entry-5">Other credits</a></h2>
420+
<p>The development and migration of this module has been financially
421+
supported by:</p>
422+
<ul class="simple">
423+
<li>Camptocamp</li>
414424
</ul>
415425
</div>
416426
<div class="section" id="maintainers">
417-
<h2><a class="toc-backref" href="#toc-entry-5">Maintainers</a></h2>
427+
<h2><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h2>
418428
<p>This module is maintained by the OCA.</p>
419429
<a class="reference external image-reference" href="https://odoo-community.org">
420430
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />

stock_product_variant_mto/tests/common.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
# Copyright 2023 Camptocamp SA
22
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
33

4-
from odoo.tests.common import Form, SavepointCase
4+
from odoo.tests import Form, tagged
55

6+
from odoo.addons.base.tests.common import BaseCommon
67

7-
class TestMTOVariantCommon(SavepointCase):
8-
at_install = False
9-
post_install = True
108

9+
@tagged("post_install", "-at_install")
10+
class TestMTOVariantCommon(BaseCommon):
1111
@classmethod
1212
def setUpClass(cls):
1313
super().setUpClass()
14-
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
1514
cls.setUpClassProduct()
1615

1716
@classmethod
@@ -79,13 +78,13 @@ def toggle_is_mto(self, records):
7978
record.is_mto = not record.is_mto
8079

8180
def assertVariantsMTO(self, records):
82-
records.invalidate_cache(["is_mto"])
81+
records.invalidate_recordset(["is_mto"])
8382
self.assertTrue(all([record.is_mto for record in records]))
8483
for rec in records:
8584
self.assertIn(self.mto_route, rec.route_ids)
8685

8786
def assertVariantsNotMTO(self, records):
88-
records.invalidate_cache(["is_mto"])
87+
records.invalidate_recordset(["is_mto"])
8988
self.assertFalse(any([record.is_mto for record in records]))
9089
for rec in records:
9190
self.assertNotIn(self.mto_route, rec.route_ids)

stock_product_variant_mto/tests/test_mto_variant.py

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
from .common import TestMTOVariantCommon
66

7+
onchange_logger = "odoo.tests.form.onchange"
8+
9+
_logger = logging.getLogger(onchange_logger)
10+
711

812
class TestMTOVariant(TestMTOVariantCommon):
913
def test_variants_mto(self):
@@ -24,14 +28,16 @@ def test_variants_mto(self):
2428
self.assertVariantsMTO(black_pen | blue_pen)
2529
self.assertVariantsNotMTO(red_pen | green_pen)
2630
# Now enable the mto route for the template, all variants get is_mto = True
27-
self.add_route(pen_template, self.mto_route)
31+
with self.assertLogs(onchange_logger, level="WARNING"):
32+
self.add_route(pen_template, self.mto_route)
2833
self.assertVariantsMTO(pens)
2934
# Disable mto route for black_pen
3035
self.toggle_is_mto(black_pen)
3136
self.assertVariantsNotMTO(black_pen)
3237
self.assertVariantsMTO(blue_pen | green_pen | red_pen)
3338
# Disable mto route on the template, reset is_mto on variants
34-
self.remove_route(pen_template, self.mto_route)
39+
with self.assertLogs(onchange_logger, level="WARNING"):
40+
self.remove_route(pen_template, self.mto_route)
3541
self.assertVariantsNotMTO(pens)
3642

3743
def test_template_routes_updated(self):
@@ -44,7 +50,8 @@ def test_template_routes_updated(self):
4450
black_pen = self.black_pen
4551
self.assertVariantsNotMTO(pens)
4652
# If template is set to MTO, all variants are updated
47-
self.add_route(pen_template, self.mto_route)
53+
with self.assertLogs(onchange_logger, level="WARNING"):
54+
self.add_route(pen_template, self.mto_route)
4855
self.assertVariantsMTO(pens)
4956
# Now toggle a few variants to is_mto == False
5057
self.toggle_is_mto(black_pen | blue_pen)
@@ -65,43 +72,49 @@ def test_template_warnings(self):
6572
red_pen = self.red_pen
6673
green_pen = self.green_pen
6774
black_pen = self.black_pen
68-
onchange_logger = logging.getLogger("odoo.tests.common.onchange")
6975
self.assertVariantsNotMTO(pens)
76+
7077
# enable mto route for black pen
7178
self.toggle_is_mto(black_pen)
7279
self.assertVariantsMTO(black_pen)
80+
7381
# Enable mto route on the template, raise warning as is_mto is reset on variants
74-
with self.assertLogs(onchange_logger) as log:
82+
with self.assertLogs(onchange_logger, level="WARNING") as log_catcher:
7583
self.add_route(pen_template, self.mto_route)
76-
self.assertIn("WARNING", log.output[0])
77-
self.assertIn("Activating MTO route will reset", log.output[0])
84+
self.assertIn("WARNING", log_catcher.output[0])
85+
self.assertIn("Activating MTO route will reset", log_catcher.output[0])
7886
self.assertVariantsMTO(pens)
87+
7988
# Disable mto route for black pen
8089
self.toggle_is_mto(black_pen)
8190
self.assertVariantsNotMTO(black_pen)
8291
self.assertVariantsMTO(blue_pen | green_pen | red_pen)
92+
8393
# Enable unrelated route does not raise warning nor reset
8494
random_route = self.mto_route.create({"name": "loutourout de la vit"})
85-
with self.assertLogs(onchange_logger) as log:
95+
with self.assertLogs(onchange_logger) as log_catcher:
8696
self.add_route(pen_template, random_route)
87-
onchange_logger.info("No warning raised")
88-
self.assertNotIn("WARNING", log.output[0])
97+
_logger.info("No warning raised")
98+
self.assertNotIn("WARNING", log_catcher.output[0])
8999
self.assertVariantsNotMTO(black_pen)
90100
self.assertVariantsMTO(blue_pen | green_pen | red_pen)
91-
# Disable mto route on the template, raise warning as is_mto is reset on variants
92-
with self.assertLogs(onchange_logger) as log:
101+
102+
# Disable mto route on the template,
103+
# raise warning as is_mto is reset on variants
104+
with self.assertLogs(onchange_logger) as log_catcher:
93105
self.remove_route(pen_template, self.mto_route)
94-
self.assertIn("WARNING", log.output[0])
95-
self.assertIn("Deactivating MTO route will reset", log.output[0])
106+
self.assertIn("WARNING", log_catcher.output[0])
107+
self.assertIn("Deactivating MTO route will reset", log_catcher.output[0])
96108
self.assertVariantsNotMTO(pens)
109+
97110
# Enable mto route for black pen
98111
self.toggle_is_mto(black_pen)
99112
self.assertVariantsMTO(black_pen)
100113
self.assertVariantsNotMTO(blue_pen | green_pen | red_pen)
114+
101115
# Disable unrelated route does not raise warning nor reset
102-
with self.assertLogs(onchange_logger) as log:
116+
with self.assertLogs(onchange_logger) as log_catcher:
103117
self.remove_route(pen_template, random_route)
104-
onchange_logger.info("No warning raised")
105-
self.assertNotIn("WARNING", log.output[0])
118+
_logger.info("No warning raised")
106119
self.assertVariantsMTO(black_pen)
107120
self.assertVariantsNotMTO(blue_pen | green_pen | red_pen)

0 commit comments

Comments
 (0)