Skip to content

Commit

Permalink
[FIX] mrp: cancel the WOs even if it is an MO without components
Browse files Browse the repository at this point in the history
Steps to reproduce the bug:
1:/
- Create a new MO:
    - Select any product
    - Delete all components
    - Add a work order
    - Save
- Cancel the MO

Problem:
The work order is not cancelled because when we cancel a MO without components,
we only change the status of the MO but do not check if there are WOs to cancel

2:/
when the MO is cancelled, the buttons ('start', 'Pause', 'block' and 'Done') must be hidden

opw-2803052

closes #87528

Signed-off-by: William Henrotin (whe) <whe@odoo.com>
  • Loading branch information
DjamelTouati committed Mar 30, 2022
1 parent 325aaeb commit ff27b67
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 6 deletions.
2 changes: 1 addition & 1 deletion addons/mrp/models/mrp_production.py
Original file line number Diff line number Diff line change
Expand Up @@ -1329,6 +1329,7 @@ def _action_generate_backorder_wizard(self, quantity_issues):
def action_cancel(self):
""" Cancels production order, unfinished stock moves and set procurement
orders in exception """
self.workorder_ids.filtered(lambda x: x.state not in ['done', 'cancel']).action_cancel()
if not self.move_raw_ids:
self.state = 'cancel'
return True
Expand All @@ -1352,7 +1353,6 @@ def _action_cancel(self):
if finish_moves:
production._log_downside_manufactured_quantity({finish_move: (production.product_uom_qty, 0.0) for finish_move in finish_moves}, cancel=True)

self.workorder_ids.filtered(lambda x: x.state not in ['done', 'cancel']).action_cancel()
finish_moves = self.move_finished_ids.filtered(lambda x: x.state not in ('done', 'cancel'))
raw_moves = self.move_raw_ids.filtered(lambda x: x.state not in ('done', 'cancel'))

Expand Down
36 changes: 36 additions & 0 deletions addons/mrp/tests/test_cancel_mo.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,39 @@ def test_unlink_mo(self):
self.assertEqual(manufacturing_order.exists().state, 'progress')
with self.assertRaises(UserError):
manufacturing_order.unlink()

def test_cancel_mo_with_workorder(self):
"""
Create a manufacturing order without component and with a work order
and check that when you cancel the MO, the WO is also canceled.
"""

bom = self.env['mrp.bom'].create({
'product_id': self.product_2.id,
'product_tmpl_id': self.product_2.product_tmpl_id.id,
'product_uom_id': self.product_2.uom_id.id,
'consumption': 'flexible',
'product_qty': 1.0,
'operation_ids': [
(0, 0, {'name': 'test_wo', 'workcenter_id': self.workcenter_1.id, 'time_cycle': 15, 'sequence': 1}),
],
'type': 'normal',
'sequence': 2,
'bom_line_ids': []
})

# Create MO
production_form = Form(self.env['mrp.production'])
production_form.product_id = self.product_2
production_form.bom_id = bom
manufacturing_order = production_form.save()

# Check that there is no component
self.assertFalse(manufacturing_order.move_raw_ids.id)

# Cancel the MO
manufacturing_order.action_cancel()

# Check that MO and WO are canceled
self.assertEqual(manufacturing_order.state, 'cancel', "MO should be in cancel state.")
self.assertEqual(manufacturing_order.workorder_ids.state, 'cancel', 'MO work orders must be cancelled as well.')
10 changes: 5 additions & 5 deletions addons/mrp/views/mrp_workorder_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,15 @@
attrs="{'invisible': [('production_state','=', 'draft')], 'readonly': [('is_user_working', '=', True)]}"/>
<field name="state" widget="badge" decoration-success="state == 'done'" decoration-info="state not in ('done', 'cancel')" attrs="{'invisible': [('production_state', 'in', ('draft', 'done'))]}"/>
<button name="button_start" type="object" string="Start" class="btn-success"
attrs="{'invisible': ['|', '|', '|', ('production_state','in', ('draft', 'done')), ('working_state', '=', 'blocked'), ('state', '=', 'done'), ('is_user_working', '!=', False)]}"/>
attrs="{'invisible': ['|', '|', '|', ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', '=', 'done'), ('is_user_working', '!=', False)]}"/>
<button name="button_pending" type="object" string="Pause" class="btn-warning"
attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False)]}"/>
attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False)]}"/>
<button name="button_finish" type="object" string="Done" class="btn-success"
attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False)]}"/>
attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False)]}"/>
<button name="%(mrp.act_mrp_block_workcenter_wo)d" type="action" string="Block" context="{'default_workcenter_id': workcenter_id}" class="btn-danger"
attrs="{'invisible': ['|', ('production_state', 'in', ('draft', 'done')), ('working_state', '=', 'blocked')]}"/>
attrs="{'invisible': ['|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked')]}"/>
<button name="button_unblock" type="object" string="Unblock" context="{'default_workcenter_id': workcenter_id}" class="btn-danger"
attrs="{'invisible': ['|', ('production_state', 'in', ('draft', 'done')), ('working_state', '!=', 'blocked')]}"/>
attrs="{'invisible': ['|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '!=', 'blocked')]}"/>
<button name="action_open_wizard" type="object" icon="fa-external-link" class="oe_edit_only"
context="{'default_workcenter_id': workcenter_id}"/>
<field name="show_json_popover" invisible="1"/>
Expand Down

0 comments on commit ff27b67

Please sign in to comment.