[FIX] mrp: MO change the quantity to 0

Usecase to reproduce:
- Create a MO for 5 final units
- Reserve all the components
- Produce 3 units
- Post Inventory (debug mode)
- Edit/Unlock
- Edit a line to consume to an arbitrary amount of quantity
- Change the product qty and set it to 3.

At this point, the reserved quantity and the quantity to consume
still the same than intialy even if the final quantity was updated.

- Mark as done

Then a move is marked as done withtout quantity done and still have
reserved quantity.

It happens because the _update_raw_move function do nothing if the
new quantity to consume is equals to 0.

The arguments returns in _update_raw_move still exists for override
but are not used by the chang_prod_qty method. It's not possible to
cancel the move and then find its parents in order to log the activity.

opw-2023653

closes odoo/odoo#34471

Signed-off-by: Arnold Moyaux <amoyaux@users.noreply.github.com>
This commit is contained in:
Arnold Moyaux
2019-07-15 11:52:47 +00:00
parent d9b7cc7ab7
commit ccbd6712f6
3 changed files with 58 additions and 4 deletions
+3 -2
View File
@@ -509,12 +509,13 @@ class MrpProduction(models.Model):
move[0]._recompute_state()
move[0]._action_assign()
move[0].unit_factor = quantity / move[0].raw_material_production_id.product_qty
elif quantity < 0: # Do not remove 0 lines
return move[0], old_qty, quantity
else:
if move[0].quantity_done > 0:
raise UserError(_('Lines need to be deleted, but can not as you still have some quantities to consume in them. '))
move[0]._action_cancel()
move[0].unlink()
return move[0], old_qty, quantity
return self.env['stock.move'], old_qty, quantity
else:
move = self._generate_raw_move(bom_line, line_data)
return move, 0, quantity
+46
View File
@@ -5,6 +5,7 @@ from odoo.tests import Form
from datetime import datetime, timedelta
from odoo.fields import Datetime as Dt
from odoo.exceptions import UserError
from odoo.addons.mrp.tests.common import TestMrpCommon
@@ -677,6 +678,51 @@ class TestMrpOrder(TestMrpCommon):
self.assertEqual(mo.move_raw_ids.filtered(lambda m: m.product_id == p1).quantity_done, 20, 'Update the produce quantity should not impact already produced quantity.')
mo.button_mark_done()
def test_product_produce_6(self):
""" Plan 5 finished products, reserve and produce 3. Post the current production.
Simulate an unlock and edit and, on the opened moves, set the consumed quantity
to 3. Now, try to update the quantity to produce to 3. It should fail since there
are consumed quantities. Unlock and edit, remove the consumed quantities and
update the quantity to produce to 3."""
self.stock_location = self.env.ref('stock.stock_location_stock')
mo, bom, p_final, p1, p2 = self.generate_mo()
self.assertEqual(len(mo), 1, 'MO should have been created')
self.env['stock.quant']._update_available_quantity(p1, self.stock_location, 20)
self.env['stock.quant']._update_available_quantity(p2, self.stock_location, 5)
mo.action_assign()
produce_wizard = self.env['mrp.product.produce'].with_context({
'active_id': mo.id,
'active_ids': [mo.id],
}).create({
'product_qty': 3.0,
})
produce_wizard._onchange_product_qty()
produce_wizard.do_produce()
mo.post_inventory()
self.assertEqual(len(mo.move_raw_ids), 4)
mo.move_raw_ids.filtered(lambda m: m.state != 'done')[0].quantity_done = 3
update_quantity_wizard = self.env['change.production.qty'].create({
'mo_id': mo.id,
'product_qty': 3,
})
with self.assertRaises(UserError):
update_quantity_wizard.change_prod_qty()
mo.move_raw_ids.filtered(lambda m: m.state != 'done')[0].quantity_done = 0
update_quantity_wizard.change_prod_qty()
self.assertEqual(len(mo.move_raw_ids), 2)
mo.button_mark_done()
self.assertTrue(all(s == 'done' for s in mo.move_raw_ids.mapped('state')))
self.assertEqual(sum(mo.move_raw_ids.mapped('move_line_ids.product_uom_qty')), 0)
def test_product_produce_uom(self):
plastic_laminate = self.env.ref('mrp.product_product_plastic_laminate')
bom = self.env.ref('mrp.mrp_bom_plastic_laminate')
+9 -2
View File
@@ -54,15 +54,22 @@ class ChangeProductionQty(models.TransientModel):
boms, lines = production.bom_id.explode(production.product_id, factor, picking_type=production.bom_id.picking_type_id)
documents = {}
for line, line_data in lines:
move, old_qty, new_qty = production._update_raw_move(line, line_data)
move = production.move_raw_ids.filtered(lambda x: x.bom_line_id.id == line.id and x.state not in ('done', 'cancel'))
if move:
old_qty = move[0].product_uom_qty
else:
old_qty = 0
iterate_key = production._get_document_iterate_key(move)
if iterate_key:
document = self.env['stock.picking']._log_activity_get_documents({move: (new_qty, old_qty)}, iterate_key, 'UP')
document = self.env['stock.picking']._log_activity_get_documents({move: (line_data['qty'], old_qty)}, iterate_key, 'UP')
for key, value in document.items():
if documents.get(key):
documents[key] += [value]
else:
documents[key] = [value]
production._update_raw_move(line, line_data)
production._log_manufacture_exception(documents)
operation_bom_qty = {}
for bom, bom_data in boms: