[FIX] mrp: replace workcenter times when specific capacity is defined

Currently, when a specific capacity is defined for a product in a
workcenter, if a setup / cleanup time is given, it will be added to the
existing setup / cleanup time of the workcenter.

What we want instead is to be able to fully define what the
setup/cleanup time is for this specific product. So the given times in
the specific capacity override the times defined in the workcenter for
that specific product.

To help with that, we set the workcenter's setup/cleanup time as a
default for their related specific capacities, since if not changed,
they will follow the workcenter times.

Updated the tests so their specified capacities match the new behaviour.

closes odoo/odoo#119212

Related: odoo/upgrade#4576
Signed-off-by: Tiffany Chang <tic@odoo.com>
This commit is contained in:
clesgow
2023-05-15 18:50:16 +02:00
parent 5de4c6dca1
commit 2f73020e08
5 changed files with 57 additions and 13 deletions
+12 -6
View File
@@ -299,12 +299,10 @@ class MrpWorkcenter(models.Model):
def _get_expected_duration(self, product_id):
"""Compute the expected duration when using this work-center
Always include workcenter startup time and clean-up time.
In case there are specific capacities defined in the workcenter
that matches the product we are producing. Add the extra-time.
Always use the startup / clean-up time from specific capacity if defined.
"""
capacity = self.capacity_ids.filtered(lambda p: p.product_id == product_id)
return self.time_start + self.time_stop + (capacity.time_start + capacity.time_stop if capacity else 0.0)
return capacity.time_start + capacity.time_stop if capacity else self.time_start + self.time_stop
class WorkcenterTag(models.Model):
@@ -478,12 +476,20 @@ class MrpWorkCenterCapacity(models.Model):
_description = 'Work Center Capacity'
_check_company_auto = True
def _default_time_start(self):
workcenter_id = self.workcenter_id.id or self.env.context.get('default_workcenter_id')
return self.env['mrp.workcenter'].browse(workcenter_id).time_start if workcenter_id else 0.0
def _default_time_stop(self):
workcenter_id = self.workcenter_id.id or self.env.context.get('default_workcenter_id')
return self.env['mrp.workcenter'].browse(workcenter_id).time_stop if workcenter_id else 0.0
workcenter_id = fields.Many2one('mrp.workcenter', string='Work Center', required=True)
product_id = fields.Many2one('product.product', string='Product', required=True)
product_uom_id = fields.Many2one('uom.uom', string='Product UoM', related='product_id.uom_id')
capacity = fields.Float('Capacity', default=1.0, help="Number of pieces that can be produced in parallel for this product.")
time_start = fields.Float('Setup Time (minutes)', help="Time in minutes for the setup.")
time_stop = fields.Float('Cleanup Time (minutes)', help="Time in minutes for the cleaning.")
time_start = fields.Float('Setup Time (minutes)', default=_default_time_start, help="Time in minutes for the setup.")
time_stop = fields.Float('Cleanup Time (minutes)', default=_default_time_stop, help="Time in minutes for the cleaning.")
_sql_constraints = [
('positive_capacity', 'CHECK(capacity > 0)', 'Capacity should be a positive number.'),
+3 -3
View File
@@ -602,8 +602,8 @@ class TestBoM(TestMrpCommon):
self.env['mrp.workcenter.capacity'].create({
'product_id': cheese_cake.id,
'workcenter_id': workcenter_2.id,
'time_start': 2,
'time_stop': 1,
'time_start': 12,
'time_stop': 16,
})
with Form(bom_cheese_cake) as bom:
@@ -628,7 +628,7 @@ class TestBoM(TestMrpCommon):
# TEST CHEESE BOM STRUCTURE VALUE WITH BOM QUANTITY
report_values = self.env['report.mrp.report_bom_structure']._get_report_data(bom_id=bom_cheese_cake.id, searchQty=60, searchVariant=False)
#Operation time = 15 min * 60 + time_start + time_stop + capacity_time_start + capacity_time_stop= 928
# Operation time = 15 min * 60 + capacity_time_start + capacity_time_stop = 928
self.assertEqual(report_values['lines']['operations_time'], 928.0, 'Operation time should be the same for 1 unit or for the batch')
# Operation cost is the sum of operation line : (60 * 10)/60 * 10€ + (10 + 15 + 60 * 5)/60 * 20€ + (1 + 2)/60 * 20€ = 209,33€
self.assertEqual(float_compare(report_values['lines']['operations_cost'], 209.33, precision_digits=2), 0)
+38
View File
@@ -3239,3 +3239,41 @@ class TestMrpOrder(TestMrpCommon):
mo_form.picking_type_id = warehouse02.manu_type_id
mo_form.bom_id = bom_wh02
self.assertEqual(mo_form.picking_type_id, warehouse01.manu_type_id, 'Should be adapted because of the default value')
def test_workcenter_specific_capacities(self):
""" Test that the duraction expected is correctly computed when specific capacities are defined on the workcenter.
"""
# Required for `workorder_ids` to be visible in the view
self.env.user.groups_id += self.env.ref('mrp.group_mrp_routings')
self.workcenter_2.update({
'time_start': 10,
'time_stop': 20,
})
self.env['mrp.workcenter.capacity'].create({
'product_id': self.product_4.id,
'workcenter_id': self.workcenter_2.id,
'time_start': 5,
'time_stop': 10,
})
production_form = Form(self.env['mrp.production'])
production_form.product_id = self.product_5
production = production_form.save()
with Form(production) as mo_form:
with mo_form.workorder_ids.new() as wo:
wo.name = "OP1"
wo.workcenter_id = self.workcenter_2
# Since no duration was given, only duration from the workcenter setup/cleanup time should be added in : 10 + 20 = 30
self.assertEqual(production.workorder_ids[0].duration_expected, 30.0, "Workcenter setup time (10) + workcenter cleanup time (20)")
# Change the product so that it uses a specific capacity of that workcenter
with Form(production) as mo_form:
mo_form.product_id = self.product_4
with mo_form.workorder_ids.new() as wo:
wo.name = "OP1"
wo.workcenter_id = self.workcenter_2
# Only duration from the workcenter specific capacity setup/cleanup times since there is one defined for this product.
self.assertEqual(production.workorder_ids[0].duration_expected, 15.0, "Capacity setup time (5) + capacity cleanup time (10)")
+2 -2
View File
@@ -392,8 +392,8 @@
<field name="product_id"/>
<field name="product_uom_id" groups="uom.group_uom"/>
<field name="capacity"/>
<field name="time_start" optional="hide"/>
<field name="time_stop" optional="hide"/>
<field name="time_start" widget="float_time"/>
<field name="time_stop" widget="float_time"/>
</tree>
</field>
</page>
+2 -2
View File
@@ -124,8 +124,8 @@ class TestBomPrice(TestBomPriceCommon):
self.env['mrp.workcenter.capacity'].create({
'product_id': self.dining_table.id,
'workcenter_id': workcenter_1.id,
'time_start': 2,
'time_stop': 1,
'time_start': 17,
'time_stop': 16,
})
self.bom_1.write({