[FIX] mrp: validate a MO with manual consumption
Steps to reproduce the bug:
- Create a storable produce P1 with BoM:
- select any component, qty: 1 unit
- Create a MO to produce one unit of P1
- Confirm the MO
- Update the qty of the component to 2
- Validate the MO
Problem:
The quantity of the component is overwritten and reset to 1
Because, when the new qty of the component is set, only the
“manual_consumption” field is updated to “True” thanks to their compute:
https://github.com/odoo/odoo/blob/17.0/addons/mrp/models/stock_move.py#L138-L145
But the field ‘picked’, is not updated
So when we check if we have to set a quantity, the condition is false
and the quantity is reset to the original value:
https://github.com/odoo/odoo/blob/26193fdb707a631d498cbc37d68c08497e32a31d/addons/mrp/models/mrp_production.py#L1201-L1202
opw-3616628
closes odoo/odoo#145157
Signed-off-by: William Henrotin (whe) <whe@odoo.com>
This commit is contained in:
@@ -287,6 +287,8 @@ class StockMove(models.Model):
|
|||||||
def write(self, vals):
|
def write(self, vals):
|
||||||
if self.env.context.get('force_manual_consumption'):
|
if self.env.context.get('force_manual_consumption'):
|
||||||
vals['manual_consumption'] = True
|
vals['manual_consumption'] = True
|
||||||
|
if vals.get('manual_consumption'):
|
||||||
|
self.picked = True
|
||||||
if 'product_uom_qty' in vals and 'move_line_ids' in vals:
|
if 'product_uom_qty' in vals and 'move_line_ids' in vals:
|
||||||
# first update lines then product_uom_qty as the later will unreserve
|
# first update lines then product_uom_qty as the later will unreserve
|
||||||
# so possibly unlink lines
|
# so possibly unlink lines
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export class MrpConsumed extends FloatField {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onInput(ev) {
|
onInput(ev) {
|
||||||
return this.props.record.update({ manual_consumption: true });
|
return this.props.record.update({ manual_consumption: true, picked: true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,3 +70,37 @@ registry.category("web_tour.tours").add('test_mrp_manual_consumption', {
|
|||||||
},
|
},
|
||||||
...stepUtils.saveForm(),
|
...stepUtils.saveForm(),
|
||||||
]});
|
]});
|
||||||
|
|
||||||
|
registry.category("web_tour.tours").add('test_mrp_manual_consumption_02', {
|
||||||
|
test: true,
|
||||||
|
steps: () => [
|
||||||
|
{
|
||||||
|
trigger: 'div[name=move_raw_ids] td[name="quantity"]:last:contains("0.00")',
|
||||||
|
run: () => {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
trigger: 'div[name=move_raw_ids] td[name="quantity"]:last',
|
||||||
|
run: 'click',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
trigger: 'div[name="quantity"] input',
|
||||||
|
run: 'text 16.0'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
content: "Click Pager",
|
||||||
|
trigger: ".o_pager_value:first()",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
trigger: "input[id='qty_producing_0']",
|
||||||
|
run: 'text 8.0',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
content: "Click Pager",
|
||||||
|
trigger: ".o_pager_value:first()",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
trigger: 'div[name=move_raw_ids] td[name="quantity"]:last:contains("16.00")',
|
||||||
|
run: () => {},
|
||||||
|
},
|
||||||
|
...stepUtils.saveForm(),
|
||||||
|
]});
|
||||||
|
|||||||
@@ -86,6 +86,50 @@ class TestTourManualConsumption(HttpCase):
|
|||||||
self.assertEqual(move_sn.manual_consumption, True)
|
self.assertEqual(move_sn.manual_consumption, True)
|
||||||
self.assertEqual(move_lot.manual_consumption, True)
|
self.assertEqual(move_lot.manual_consumption, True)
|
||||||
|
|
||||||
|
def test_mrp_manual_consumption_02(self):
|
||||||
|
"""
|
||||||
|
test that when a new quantity is manually set for a component,
|
||||||
|
and the MO is marked as done, the component quantity is not overwritten.
|
||||||
|
"""
|
||||||
|
Product = self.env['product.product']
|
||||||
|
product_finish = Product.create({
|
||||||
|
'name': 'finish',
|
||||||
|
'type': 'product',
|
||||||
|
'tracking': 'none',})
|
||||||
|
product_nt = Product.create({
|
||||||
|
'name': 'No tracking',
|
||||||
|
'type': 'product',
|
||||||
|
'tracking': 'none',})
|
||||||
|
bom = self.env['mrp.bom'].create({
|
||||||
|
'product_id': product_finish.id,
|
||||||
|
'product_tmpl_id': product_finish.product_tmpl_id.id,
|
||||||
|
'product_qty': 1,
|
||||||
|
'type': 'normal',
|
||||||
|
'bom_line_ids': [
|
||||||
|
(0, 0, {'product_id': product_nt.id, 'product_qty': 1}),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
mo_form = Form(self.env['mrp.production'])
|
||||||
|
mo_form.product_id = product_finish
|
||||||
|
mo_form.bom_id = bom
|
||||||
|
mo_form.product_qty = 10
|
||||||
|
mo = mo_form.save()
|
||||||
|
mo.action_confirm()
|
||||||
|
|
||||||
|
self.assertEqual(mo.state, 'confirmed')
|
||||||
|
move_nt = mo.move_raw_ids
|
||||||
|
self.assertEqual(move_nt.manual_consumption, False)
|
||||||
|
self.assertEqual(move_nt.quantity, 0)
|
||||||
|
self.assertFalse(move_nt.picked)
|
||||||
|
|
||||||
|
action_id = self.env.ref('mrp.menu_mrp_production_action').action
|
||||||
|
url = "/web#model=mrp.production&view_type=form&action=%s&id=%s" % (str(action_id.id), str(mo.id))
|
||||||
|
self.start_tour(url, "test_mrp_manual_consumption_02", login="admin", timeout=100)
|
||||||
|
|
||||||
|
self.assertEqual(move_nt.manual_consumption, True)
|
||||||
|
self.assertEqual(move_nt.picked, True)
|
||||||
|
self.assertEqual(move_nt.quantity, 16.0)
|
||||||
|
|
||||||
class TestManualConsumption(TestMrpCommon):
|
class TestManualConsumption(TestMrpCommon):
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
Reference in New Issue
Block a user