Skip to content

Commit

Permalink
[FIX] mrp_subcontracting: avoid full cancel when multiple step record
Browse files Browse the repository at this point in the history
Steps to reproduce:
- Create a subcontracted BoM for a product
- Create a planned reception for this product, with a demand of 10, mark
it as todo.
- Click on the moves details and in the 'Subcontract' wizard, set the
quantity to 5 and click 'Continue'.
- Now set the quantity to 2 and click 'Record Production'.
- Close the wizard without recording the last quantity.
- Validate the picking (there should be only 7 out of 10 quantity done),
and don't generate backorders.
- When checking the related Subcontracted MO (Inventory Overview ->
Filters -> Archived -> Subcontracting), all 3 MO related to this
reception were cancelled.

Issue:
When checking for the still active_productions, it wasn't taking into
account that there could be multiple still-active productions (like when
a production is recorded in multiple times like here). This messes up
with the 'in' condition, cancelling productions that shouldn't be.

Task-3383596

Part-of: odoo#129009
  • Loading branch information
clesgow committed Oct 6, 2023
1 parent 0dc4215 commit f4ec447
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 4 deletions.
9 changes: 5 additions & 4 deletions addons/mrp_subcontracting/models/stock_move.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,10 +203,11 @@ def _set_quantities_to_reservation(self):
def _action_cancel(self):
for move in self:
if move.is_subcontract:
active_production = move.move_orig_ids.production_id.filtered(lambda p: p.state not in ('done', 'cancel'))
moves = self.env.context.get('moves_todo')
if not moves or active_production not in moves.move_orig_ids.production_id:
active_production.with_context(skip_activity=True).action_cancel()
active_productions = move.move_orig_ids.production_id.filtered(lambda p: p.state not in ('done', 'cancel'))
moves_todo = self.env.context.get('moves_todo')
not_todo_productions = active_productions.filtered(lambda p: p not in moves_todo.move_orig_ids.production_id) if moves_todo else active_productions
if not_todo_productions:
not_todo_productions.with_context(skip_activity=True).action_cancel()
return super()._action_cancel()

def _action_confirm(self, merge=True, merge_into=False):
Expand Down
41 changes: 41 additions & 0 deletions addons/mrp_subcontracting/tests/test_subcontracting.py
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,47 @@ def test_change_reception_serial(self):
self.assertEqual(len(subcontracted_mo.filtered(lambda p: p.lot_producing_id == new_lot)), 1)
self.assertEqual(len(subcontracted_mo.filtered(lambda p: p.lot_producing_id != new_lot)), 2)

def test_multiple_component_records_for_incomplete_move(self):
self.bom.consumption = 'flexible'
with Form(self.env['stock.picking']) as picking_form:
picking_form.picking_type_id = self.env.ref('stock.picking_type_in')
picking_form.partner_id = self.subcontractor_partner1
with picking_form.move_ids_without_package.new() as move:
move.product_id = self.finished
move.product_uom_qty = 10
picking_receipt = picking_form.save()
picking_receipt.action_confirm()
move = picking_receipt.move_ids_without_package

# Register the five first finished products
action = move.action_show_details()
mo = self.env['mrp.production'].browse(action['res_id'])
with Form(mo.with_context(action['context']), view=action['view_id']) as mo_form:
mo_form.qty_producing = 5
mo_form.save()
mo.subcontracting_record_component()
self.assertEqual(move.quantity_done, 5)

# Register two other finished products
action = move.action_show_details()
mo = self.env['mrp.production'].browse(action['res_id'])
with Form(mo.with_context(action['context']), view=action['view_id']) as mo_form:
mo_form.qty_producing = 2
mo_form.save()
mo.subcontracting_record_component()
self.assertEqual(move.quantity_done, 7)

# Validate picking without backorder
backorder_wizard_dict = picking_receipt.button_validate()
backorder_wizard_form = Form(self.env[backorder_wizard_dict['res_model']].with_context(backorder_wizard_dict['context']))
backorder_wizard_form.save().process_cancel_backorder()

self.assertRecordValues(move._get_subcontract_production(), [
{'product_qty': 5, 'state': 'done'},
{'product_qty': 2, 'state': 'done'},
{'product_qty': 3, 'state': 'cancel'},
])


@tagged('post_install', '-at_install')
class TestSubcontractingTracking(TransactionCase):
Expand Down

0 comments on commit f4ec447

Please sign in to comment.