[FIX] mrp: use the fastest workcenter
Steps to reproduce the bug:
- Create the workcenter_1:
- Time Efficiency: 100%
- Capacity: 2
- Setup Time: 1
- Cleanup Time: 1
- Create the workcenter_2:
- Time Efficiency: 100%
- Capacity: 4
- Setup Time: 10
- Cleanup Time: 5
- Alternative Work centers: workcenter_1
- Create a storable product “P1” with BOM:
- Add any product as component
- Add operation:
- Duration: 60
- Work center: Workcenter_2
- Create a MO:
- select “P1” as Product
- Qty to produce: 4
- Confirm and Plan
Problem:
The workcenter_1 is chosen while work_center_2 is faster it can manufacture the 4 units at the same time
while workcenter_1 must do two cycles
As the Time Efficiency = 100%, so:
Total duration = (Setup Time + Cleanup Time) + duration_by_unit * nb_cycle
Work_center_1 = (1 + 1) + 60 * 2 = 122
Work_center_2 = (10 + 5) + 60 = 75
The calculation is bad because we use the number of cycles necessary for the work_center defined in the BOM
in the calculation for the alternative work center
opw-2821749
closes odoo/odoo#88945
X-original-commit: deb87a6abf8b8ccc4328eaac21430eedc2536361
Signed-off-by: Arnold Moyaux <arm@odoo.com>
Signed-off-by: Djamel Touati (otd) <otd@odoo.com>
This commit is contained in:
@@ -728,7 +728,8 @@ class MrpWorkorder(models.Model):
|
||||
duration_expected_working = (self.duration_expected - self.workcenter_id.time_start - self.workcenter_id.time_stop) * self.workcenter_id.time_efficiency / (100.0 * cycle_number)
|
||||
if duration_expected_working < 0:
|
||||
duration_expected_working = 0
|
||||
return alternative_workcenter.time_start + alternative_workcenter.time_stop + cycle_number * duration_expected_working * 100.0 / alternative_workcenter.time_efficiency
|
||||
alternative_wc_cycle_nb = float_round(qty_production / alternative_workcenter.capacity, precision_digits=0, rounding_method='UP')
|
||||
return alternative_workcenter.time_start + alternative_workcenter.time_stop + alternative_wc_cycle_nb * duration_expected_working * 100.0 / alternative_workcenter.time_efficiency
|
||||
time_cycle = self.operation_id.time_cycle
|
||||
return self.workcenter_id.time_start + self.workcenter_id.time_stop + cycle_number * time_cycle * 100.0 / self.workcenter_id.time_efficiency
|
||||
|
||||
|
||||
@@ -2651,3 +2651,80 @@ class TestMrpOrder(TestMrpCommon):
|
||||
self.assertEqual(mo_3.state, 'to_close')
|
||||
mo_3.button_mark_done()
|
||||
self.assertEqual(mo_3.state, 'done')
|
||||
|
||||
def test_planning_workorder(self):
|
||||
"""
|
||||
Check that the fastest work center is used when planning the workorder.
|
||||
- create two work centers with similar production capacity
|
||||
but the work_center_2 with a longer start and stop time.
|
||||
1:/ produce 2 units > work_center_1 faster because
|
||||
it does not need much time to start and to finish the production.
|
||||
2/ - update the production capacity of the work_center_2 to 4
|
||||
- produce 4 units > work_center_2 faster because
|
||||
it must do a single cycle while the work_center_1 have to do two cycles.
|
||||
"""
|
||||
workcenter_1 = self.env['mrp.workcenter'].create({
|
||||
'name': 'wc1',
|
||||
'capacity': 2,
|
||||
'time_start': 1,
|
||||
'time_stop': 1,
|
||||
'time_efficiency': 100,
|
||||
})
|
||||
|
||||
workcenter_2 = self.env['mrp.workcenter'].create({
|
||||
'name': 'wc2',
|
||||
'capacity': 2,
|
||||
'time_start': 10,
|
||||
'time_stop': 5,
|
||||
'time_efficiency': 100,
|
||||
'alternative_workcenter_ids': [workcenter_1.id]
|
||||
})
|
||||
|
||||
product_to_build = self.env['product.product'].create({
|
||||
'name': 'final product',
|
||||
'type': 'product',
|
||||
})
|
||||
|
||||
product_to_use = self.env['product.product'].create({
|
||||
'name': 'component',
|
||||
'type': 'product',
|
||||
})
|
||||
|
||||
bom = self.env['mrp.bom'].create({
|
||||
'product_id': product_to_build.id,
|
||||
'product_tmpl_id': product_to_build.product_tmpl_id.id,
|
||||
'product_uom_id': self.uom_unit.id,
|
||||
'product_qty': 1.0,
|
||||
'type': 'normal',
|
||||
'consumption': 'flexible',
|
||||
'operation_ids': [
|
||||
(0, 0, {'name': 'Test', 'workcenter_id': workcenter_2.id, 'time_cycle': 60, 'sequence': 1}),
|
||||
],
|
||||
'bom_line_ids': [
|
||||
(0, 0, {'product_id': product_to_use.id, 'product_qty': 1}),
|
||||
]})
|
||||
|
||||
#MO_1
|
||||
mo_form = Form(self.env['mrp.production'])
|
||||
mo_form.product_id = product_to_build
|
||||
mo_form.bom_id = bom
|
||||
mo_form.product_qty = 2
|
||||
mo = mo_form.save()
|
||||
mo.action_confirm()
|
||||
mo.button_plan()
|
||||
self.assertEqual(mo.workorder_ids[0].workcenter_id.id, workcenter_1.id, 'workcenter_1 is faster than workcenter_2 to manufacture 2 units')
|
||||
# Unplan the mo to prevent the first workcenter from being busy
|
||||
mo.button_unplan()
|
||||
|
||||
# Update the production capcity
|
||||
workcenter_2.capacity = 4
|
||||
|
||||
#MO_2
|
||||
mo_form = Form(self.env['mrp.production'])
|
||||
mo_form.product_id = product_to_build
|
||||
mo_form.bom_id = bom
|
||||
mo_form.product_qty = 4
|
||||
mo_2 = mo_form.save()
|
||||
mo_2.action_confirm()
|
||||
mo_2.button_plan()
|
||||
self.assertEqual(mo_2.workorder_ids[0].workcenter_id.id, workcenter_2.id, 'workcenter_2 is faster than workcenter_1 to manufacture 4 units')
|
||||
|
||||
Reference in New Issue
Block a user