# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import Command from odoo.addons.mrp.tests import common from odoo.tests import Form class TestWorkOrderDependencies(common.TestMrpCommon): @classmethod def setUpClass(cls): super().setUpClass() cls.wkct1 = cls.env['mrp.workcenter'].create({ 'name': 'Workcenter#1', }) cls.wkct2 = cls.env['mrp.workcenter'].create({ 'name': 'Workcenter#2', }) cls.wkct3 = cls.env['mrp.workcenter'].create({ 'name': 'Workcenter#3', }) cls.finished = cls.env['product.product'].create({ 'name': 'Finished Product', 'type': 'product', }) cls.component1 = cls.env['product.product'].create({ 'name': 'Component#1', 'type': 'product', }) cls.component2 = cls.env['product.product'].create({ 'name': 'Component#2', 'type': 'product', }) cls.bom = cls.env['mrp.bom'].create({ 'product_id': cls.finished.id, 'product_tmpl_id': cls.finished.product_tmpl_id.id, 'product_qty': 1.0, 'bom_line_ids': [ Command.create({'product_id': cls.component1.id, 'product_qty': 1}), Command.create({'product_id': cls.component2.id, 'product_qty': 2}) ], 'operation_ids': [ Command.create({'name': 'Operation#A', 'workcenter_id': cls.wkct1.id}), Command.create({'name': 'Operation#B', 'workcenter_id': cls.wkct2.id}), Command.create({'name': 'Operation#C', 'workcenter_id': cls.wkct3.id}), ], 'allow_operation_dependencies': True, }) cls.stock_location = cls.env.ref('stock.stock_location_stock') cls.env['stock.quant']._update_available_quantity(cls.component1, cls.stock_location, 100) cls.env['stock.quant']._update_available_quantity(cls.component2, cls.stock_location, 100) def test_parallel_workorders(self): """ Test parallel workorders: bom allowing operation dependencies without any dependency.""" # Make MO mo_form = Form(self.env['mrp.production']) mo_form.product_id = self.finished mo_form.product_qty = 2.0 mo = mo_form.save() mo.action_confirm() # Check workorders initial state self.assertEqual(mo.workorder_ids[0].state, 'ready', "All workorders should be ready.") self.assertEqual(mo.workorder_ids[1].state, 'ready', "All workorders should be ready.") self.assertEqual(mo.workorder_ids[2].state, 'ready', "All workorders should be ready.") def test_stepped_workorders(self): """ Test step-by-step workorders: bom operations are interdependent.""" # Make 1st workorder depend on 3rd self.bom.operation_ids[0].blocked_by_operation_ids = [Command.link(self.bom.operation_ids[2].id)] # Make MO mo_form = Form(self.env['mrp.production']) mo_form.product_id = self.finished mo_form.product_qty = 2.0 mo = mo_form.save() mo.action_confirm() wo1, wo2, wo3 = mo.workorder_ids # Check workorders initial state self.assertEqual(wo1.state, 'pending', "Workorder for Operation-A should be Waiting for another WO (the 3rd).") self.assertEqual(wo2.state, 'ready', "Workorder for Operation-B should be ready.") self.assertEqual(wo3.state, 'ready', "Workorder for Operation-C should be ready.") mo.button_plan() # Mark 1st initial WO as done wo2.button_start() wo2.qty_producing = 2 wo2.record_production() # Check 3rd WO (not dependent on 1st) self.assertEqual(wo1.state, 'pending', "Workorder for Operation-A should STILL be Waiting for another WO (the 3rd).") # Mark 2nd initial WO as done wo3.button_start() wo3.qty_producing = 2 wo3.record_production() # Check dependent WO self.assertEqual(wo1.state, 'ready', "Workorder for Operation-A can be started, as its predecessors are now done.") def test_propagate_quantity_on_backorders_with_stepped_workorders(self): """Create a MO for a product with several work orders. Produce different quantities to test quantity propagation and workorder cancellation. -> Reproduce test_propagate_quantity_on_backorders on stepped workorders """ # Make 1st workorder depend on 3rd self.bom.operation_ids[0].blocked_by_operation_ids = [Command.link(self.bom.operation_ids[2].id)] # Make MO for 20 products mo_form = Form(self.env['mrp.production']) mo_form.product_id = self.finished mo_form.product_qty = 20 mo = mo_form.save() self.assertEqual(mo.state, 'draft') mo.action_confirm() wo_1, wo_2, wo_3 = mo.workorder_ids self.assertEqual(mo.state, 'confirmed') self.assertEqual(wo_1.state, 'pending') self.assertEqual(wo_2.state, 'ready') self.assertEqual(wo_3.state, 'ready') # produce 20 / 10 / 5 on workorders 2 / 3 / 1, mark as done & create backorder # mo closed with 5 produced # backorder for 15 created with # - wo5 'cancel' (fully processed) # - wo6 'ready' for 10 # - wo4 'pending' for 15 wo_2.button_start() wo_2.qty_producing = 20 self.assertEqual(mo.state, 'progress') wo_2.button_finish() wo_3.button_start() wo_3.qty_producing = 10 wo_3.button_finish() wo_1.button_start() wo_1.qty_producing = 5 wo_1.button_finish() self.assertEqual(mo.state, 'to_close') mo.button_mark_done() bo = self.env['mrp.production.backorder'].create({ "mrp_production_backorder_line_ids": [ [0, 0, {"mrp_production_id": mo.id, "to_backorder": True}] ] }) bo.action_backorder() self.assertEqual(mo.state, 'done') mo_2 = mo.procurement_group_id.mrp_production_ids - mo wo_4, wo_5, wo_6 = mo_2.workorder_ids self.assertEqual(wo_4.state, 'pending') self.assertEqual(wo_5.state, 'cancel') self.assertEqual(wo_6.state, 'ready') # produce 10 / 5 on workorders 6 / 4, mark as done & create backorder # mo closed with 5 produced # backorder for 10 created with # - wo8 'cancel' (already fully processed) # - wo9 'cancel' (fully processed) # - wo7 'ready' for 10 wo_6.button_start() wo_6.qty_producing = 10 self.assertEqual(mo_2.state, 'progress') wo_6.button_finish() wo_4.button_start() wo_4.qty_producing = 5 wo_4.button_finish() self.assertEqual(mo_2.state, 'to_close') mo_2.button_mark_done() bo = self.env['mrp.production.backorder'].create({ "mrp_production_backorder_line_ids": [ [0, 0, {"mrp_production_id": mo_2.id, "to_backorder": True}] ] }) bo.action_backorder() self.assertEqual(mo_2.state, 'done') mo_3 = mo.procurement_group_id.mrp_production_ids - (mo | mo_2) wo_7, wo_8, wo_9 = mo_3.workorder_ids self.assertEqual(wo_7.state, 'ready') self.assertEqual(wo_8.state, 'cancel') self.assertEqual(wo_9.state, 'cancel') # produce 10 on workorder 7 and finish work wo_7.button_start() wo_7.qty_producing = 10 self.assertEqual(mo_3.state, 'progress') wo_7.button_finish() self.assertEqual(mo_3.state, 'to_close') mo_3.button_mark_done() self.assertEqual(mo_3.state, 'done')