diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py index 9cc93e8171c..71144857538 100644 --- a/addons/mrp/models/mrp_production.py +++ b/addons/mrp/models/mrp_production.py @@ -1305,9 +1305,10 @@ class MrpProduction(models.Model): for workorder in final_workorders: workorder._plan_workorder(replan) + workorders = self.workorder_ids.filtered(lambda w: w.state not in ['done', 'cancel']) self.with_context(force_date=True).write({ - 'date_planned_start': min([workorder.leave_id.date_from for workorder in self.workorder_ids]), - 'date_planned_finished': max([workorder.leave_id.date_to for workorder in self.workorder_ids]) + 'date_planned_start': min([workorder.leave_id.date_from for workorder in workorders]), + 'date_planned_finished': max([workorder.leave_id.date_to for workorder in workorders]) }) def button_unplan(self): diff --git a/addons/mrp/models/mrp_workorder.py b/addons/mrp/models/mrp_workorder.py index 513297f525e..1edd079c509 100644 --- a/addons/mrp/models/mrp_workorder.py +++ b/addons/mrp/models/mrp_workorder.py @@ -505,6 +505,8 @@ class MrpWorkorder(models.Model): # Plan workorder after its predecessors start_date = max(self.production_id.date_planned_start, datetime.now()) for workorder in self.blocked_by_workorder_ids: + if workorder.state in ['done', 'cancel']: + continue workorder._plan_workorder(replan) start_date = max(start_date, workorder.date_planned_finished) # Plan only suitable workorders diff --git a/addons/mrp/tests/test_order.py b/addons/mrp/tests/test_order.py index 227a2474a33..428bc118e14 100644 --- a/addons/mrp/tests/test_order.py +++ b/addons/mrp/tests/test_order.py @@ -2965,6 +2965,86 @@ class TestMrpOrder(TestMrpCommon): self.assertEqual(op_1.date_planned_start, datetime(2022, 10, 20, 12)) self.assertTrue(op_2.show_json_popover) + @freeze_time('2023-03-01 12:00') + def test_planning_cancelled_workorder(self): + """Test when plan start time for workorders, cancelled workorders won't be taken into account. + """ + workcenter_1 = self.env['mrp.workcenter'].create({ + 'name': 'wc1', + 'default_capacity': 1, + 'time_start': 10, + 'time_stop': 5, + 'time_efficiency': 100, + }) + workcenter_2 = self.env['mrp.workcenter'].create({ + 'name': 'wc2', + 'default_capacity': 1, + 'time_start': 10, + 'time_stop': 5, + 'time_efficiency': 100, + }) + workcenter_3 = self.env['mrp.workcenter'].create({ + 'name': 'wc3', + 'default_capacity': 1, + 'time_start': 10, + 'time_stop': 5, + 'time_efficiency': 100, + }) + bom = self.env['mrp.bom'].create({ + 'product_id': self.product_6.id, + 'product_tmpl_id': self.product_6.product_tmpl_id.id, + 'product_uom_id': self.uom_unit.id, + 'ready_to_produce': 'asap', + 'consumption': 'flexible', + 'product_qty': 1.0, + 'operation_ids': [ + (0, 0, {'name': 'Cutting Machine', 'workcenter_id': workcenter_1.id, 'time_cycle_manual': 30, 'sequence': 1}), + (0, 0, {'name': 'Weld Machine', 'workcenter_id': workcenter_2.id, 'time_cycle_manual': 30, 'sequence': 2}), + (0, 0, {'name': 'Gift Wrap Machine', 'workcenter_id': workcenter_3.id, 'time_cycle_manual': 30, 'sequence': 3}), + ], + 'type': 'normal', + 'bom_line_ids': [ + (0, 0, {'product_id': self.product_2.id, 'product_qty': 1}) + ]}) + + mo_form = Form(self.env['mrp.production']) + mo_form.product_id = self.product_6 + 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].date_planned_start, datetime(2023, 3, 1, 12, 0)) + self.assertEqual(mo.workorder_ids[1].date_planned_start, datetime(2023, 3, 1, 13, 15)) + self.assertEqual(mo.workorder_ids[2].date_planned_start, datetime(2023, 3, 1, 14, 30)) + + # wo_1 completely finished + mo_form = Form(mo) + mo_form.qty_producing = 2 + mo = mo_form.save() + mo.workorder_ids[0].button_start() + mo.workorder_ids[0].button_finish() + # wo_2, wo_3 partially finished + mo_form.qty_producing = 1 + mo = mo_form.save() + mo.workorder_ids[1].button_start() + mo.workorder_ids[1].button_finish() + mo.workorder_ids[2].button_start() + mo.workorder_ids[2].button_finish() + + action = mo.button_mark_done() + backorder = Form(self.env['mrp.production.backorder'].with_context(**action['context'])) + backorder.save().action_backorder() + mo_backorder = mo.procurement_group_id.mrp_production_ids[-1] + mo_backorder.button_plan() + + self.assertEqual(mo_backorder.workorder_ids[0].state, 'cancel') + self.assertEqual(mo_backorder.workorder_ids[1].state, 'waiting') + self.assertEqual(mo_backorder.workorder_ids[2].state, 'pending') + self.assertFalse(mo_backorder.workorder_ids[0].date_planned_start) + self.assertEqual(mo_backorder.workorder_ids[1].date_planned_start, datetime(2023, 3, 1, 12, 0)) + self.assertEqual(mo_backorder.workorder_ids[2].date_planned_start, datetime(2023, 3, 1, 12, 45)) + def test_compute_product_id(self): """ Tests the creation of a production order automatically sets the product when the bom is provided,