Ensure workorder sequence is applied on new workorders

Test sequence is applied for multiple operations
Rewrite _reset_work_order_sequence in a more pythonic way
Change _order of mrp.workorder to use sequence
Set sequence on existing workorders after module install
This commit is contained in:
Akim Juillerat
2022-12-20 18:55:31 +01:00
committed by DavidJForgeFlow
parent 02a502c8c4
commit 16e40e4c16
7 changed files with 152 additions and 12 deletions

View File

@@ -1,3 +1,4 @@
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from . import models
from .hooks import post_init_hook

View File

@@ -14,4 +14,5 @@
"depends": ["mrp"],
"data": ["views/mrp_workorder_view.xml"],
"installable": True,
"post_init_hook": "post_init_hook",
}

View File

@@ -0,0 +1,11 @@
# Copyright 2022 Camptocamp SA
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
from odoo import SUPERUSER_ID, api, tools
def post_init_hook(cr, registry):
env = api.Environment(cr, SUPERUSER_ID, {})
all_workorders = env["mrp.workorder"].search([], order="production_id ASC, id ASC")
for _, workorders in tools.groupby(all_workorders, lambda w: w.production_id):
for seq, wo in enumerate(workorders, 1):
wo.sequence = seq

View File

@@ -9,12 +9,15 @@ class MrpProduction(models.Model):
def _reset_work_order_sequence(self):
for rec in self:
current_sequence = 1
for work in rec.workorder_ids:
work.sequence = current_sequence
current_sequence += 1
for current_seq, work in enumerate(rec.workorder_ids, 1):
work.sequence = current_seq
def _create_workorder(self):
res = super()._create_workorder()
# Bypass sequence assignation on create and make sure there is no gap
# using _reset_work_order_sequence
res = super(
MrpProduction,
self.with_context(_bypass_sequence_assignation_on_create=True),
)._create_workorder()
self._reset_work_order_sequence()
return res

View File

@@ -1,10 +1,42 @@
# Copyright 2019-20 ForgeFlow S.L. (https://www.forgeflow.com)
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import fields, models
from odoo import api, fields, models
class MrpWorkOrder(models.Model):
_inherit = "mrp.workorder"
_order = "production_id, sequence, id"
sequence = fields.Integer()
def _assign_sequence_on_create(self, values_list):
"""Assign sequence number for manually added operations"""
new_wos_production_ids_without_seq = {
vals["production_id"] for vals in values_list if not vals.get("sequence")
}
if new_wos_production_ids_without_seq:
max_seq_by_production = self.read_group(
[("production_id", "in", list(new_wos_production_ids_without_seq))],
["sequence:max", "production_id"],
["production_id"],
)
max_seq_by_prod_id = {
res["production_id"][0]: res["sequence"]
for res in max_seq_by_production
}
for values in values_list:
prod_id = values["production_id"]
values_seq = values.get("sequence")
max_seq = max_seq_by_prod_id.setdefault(prod_id, 0)
if values_seq and values_seq > max_seq:
max_seq_by_prod_id[prod_id] = values_seq
continue
max_seq_by_prod_id[prod_id] += 1
values["sequence"] = max_seq_by_prod_id[prod_id]
@api.model_create_multi
def create(self, values_list):
if not self.env.context.get("_bypass_sequence_assignation_on_create"):
self._assign_sequence_on_create(values_list)
return super().create(values_list)

View File

@@ -1,3 +1,4 @@
* Lois Rilo <lois.rilo@forgeflow.com>
* Pimolnat Suntian <pimolnats@ecosoft.co.th>
* Christopher Ormaza <chris.ormaza@forgeflow.com>
* Akim Juillerat <akim.juillerat@camptocamp.com>

View File

@@ -1,15 +1,19 @@
# Copyright 2022 ForgeFlow S.L. (https://www.forgeflow.com)
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import Command
from odoo import Command, fields
from odoo.tests import Form
from odoo.addons.mrp.tests.common import TestMrpCommon
class TestMrpWorkorderSequence(TestMrpCommon):
def test_mrp_workorder_sequence(self):
self.env["mrp.bom"].create(
def setUp(self):
super().setUp()
self._create_bom()
def _create_bom(self):
return self.env["mrp.bom"].create(
{
"product_tmpl_id": self.product_7_template.id,
"product_uom_id": self.uom_unit.id,
@@ -104,8 +108,95 @@ class TestMrpWorkorderSequence(TestMrpCommon):
],
}
)
def _create_order(self, product):
mrp_order_form = Form(self.env["mrp.production"])
mrp_order_form.product_id = self.product_7_3
mrp_order_form.product_id = product
return mrp_order_form.save()
def test_mrp_workorder_sequence_new_production(self):
mrp_order = self._create_order(self.product_7_1)
self.assertEqual(len(mrp_order.workorder_ids), 2)
for seq, workorder in enumerate(mrp_order.workorder_ids, 1):
self.assertEqual(workorder.sequence, seq)
def test_mrp_workorder_sequence_new_production_new_workorder(self):
mrp_order = self._create_order(self.product_7_1)
self.assertEqual(len(mrp_order.workorder_ids), 2)
max_sequence = max(mrp_order.workorder_ids.mapped("sequence"))
mrp_order_form = Form(mrp_order)
with mrp_order_form.workorder_ids.new() as wo_form:
wo_form.name = "Extra operation"
wo_form.workcenter_id = self.workcenter_1
mrp_order = mrp_order_form.save()
for workorder in mrp_order.workorder_ids:
self.assertEqual(workorder.sequence, workorder.operation_id.sequence)
self.assertEqual(len(mrp_order.workorder_ids), 3)
last_wo = fields.first(mrp_order.workorder_ids.sorted(reverse=True))
self.assertEqual(last_wo.sequence, max_sequence + 1)
def test_mrp_workorder_create_multi(self):
"""
Test automatic sequence assignation through create override
* WO 1: - each added operations without sequence defined
get the next sequence after existing WOs
* WO 2: - first added operation without sequence
get the next sequence after existing WOs
- second added operation with sequence defined stays unchanged
* WO 3: - first added operation with sequence defined stays unchanged
- second added operation without sequence defined
get the next sequence from previous operation created
"""
first_mrp_order = self._create_order(self.product_7_1)
second_mrp_order = self._create_order(self.product_7_1)
third_mrp_order = self._create_order(self.product_7_1)
create_values = [
{
"name": "Extra WO 1.1",
"production_id": first_mrp_order.id,
"workcenter_id": self.workcenter_1.id,
"product_uom_id": self.product_7_1.uom_id.id,
},
{
"name": "Extra WO 1.2",
"production_id": first_mrp_order.id,
"workcenter_id": self.workcenter_1.id,
"product_uom_id": self.product_7_1.uom_id.id,
},
{
"name": "Extra WO 2.1",
"production_id": second_mrp_order.id,
"workcenter_id": self.workcenter_1.id,
"product_uom_id": self.product_7_1.uom_id.id,
},
{
"name": "Extra WO 2.2",
"production_id": second_mrp_order.id,
"workcenter_id": self.workcenter_1.id,
"product_uom_id": self.product_7_1.uom_id.id,
"sequence": 6,
},
{
"name": "Extra WO 3.1",
"production_id": third_mrp_order.id,
"workcenter_id": self.workcenter_1.id,
"sequence": 4,
"product_uom_id": self.product_7_1.uom_id.id,
},
{
"name": "Extra WO 3.2",
"production_id": third_mrp_order.id,
"workcenter_id": self.workcenter_1.id,
"product_uom_id": self.product_7_1.uom_id.id,
},
]
created_wos = self.env["mrp.workorder"].create(create_values)
expected_res = {
"Extra WO 1.1": 3,
"Extra WO 1.2": 4,
"Extra WO 2.1": 3,
"Extra WO 2.2": 6,
"Extra WO 3.1": 4,
"Extra WO 3.2": 5,
}
for wo in created_wos:
self.assertEqual(wo.sequence, expected_res[wo.name])