[FIX] mrp: find BoM with other picking type

To reproduce the issue:
1. In Settings, enable "Multi-Step Routes"
2. Create a second warehouse WH02
   - Let WH01 be the existing one
3. Create two storable products P_compo, P_finished
4. Create a BoM:
   - Product: P_finished
   - Components: 1 x P_compo
   - Operation Type: "WH02: Manufacturing"
5. Create a MO:
   - Product: P_finished

Error: Once the product is set, nothing defines the BoM (and
therefore the components, picking type, and so on)

When opening the MO form, the picking type is directly defined with
"WH01: Manufacturing". Therefore, when looking for a BoM, we use
that picking type as criteria -> we will not find the BoM of step 4

Notes about the fix:
- Small behaviour change: once the picking type is set, it does not
change automaticaly (whatever the BoM is)

OPW-3122384

closes odoo/odoo#116515

X-original-commit: 93381af48e20a10c3fded88f010f89cd03cc5131
Signed-off-by: William Henrotin (whe) <whe@odoo.com>
Signed-off-by: Adrien Widart <awt@odoo.com>
This commit is contained in:
Adrien Widart (awt)
2023-03-24 19:21:25 +01:00
parent 6540757d4a
commit 34c55c5e54
2 changed files with 74 additions and 4 deletions
+12 -4
View File
@@ -282,7 +282,12 @@ class MrpProduction(models.Model):
]
picking_types = self.env['stock.picking.type'].search_read(domain, ['company_id'], load=False, limit=1)
picking_type_by_company = {pt['company_id']: pt['id'] for pt in picking_types}
default_picking_type_id = self._context.get('default_picking_type_id')
default_picking_type = default_picking_type_id and self.env['stock.picking.type'].browse(default_picking_type_id)
for mo in self:
if default_picking_type and default_picking_type.company_id == mo.company_id:
mo.picking_type_id = default_picking_type_id
continue
if mo.bom_id and mo.bom_id.picking_type_id:
mo.picking_type_id = mo.bom_id.picking_type_id
continue
@@ -345,21 +350,24 @@ class MrpProduction(models.Model):
):
production.product_id = bom.product_id or bom.product_tmpl_id.product_variant_id
@api.depends('product_id', 'picking_type_id')
@api.depends('product_id')
def _compute_bom_id(self):
mo_by_picking_type_and_company_id = defaultdict(lambda: self.env['mrp.production'])
mo_by_company_id = defaultdict(lambda: self.env['mrp.production'])
for mo in self:
if not mo.product_id and not mo.bom_id:
mo.bom_id = False
continue
mo_by_picking_type_and_company_id[(mo.picking_type_id, mo.company_id.id)] |= mo
mo_by_company_id[mo.company_id.id] |= mo
for (picking_type, company_id), productions in mo_by_picking_type_and_company_id.items():
for company_id, productions in mo_by_company_id.items():
picking_type_id = self._context.get('default_picking_type_id')
picking_type = picking_type_id and self.env['stock.picking.type'].browse(picking_type_id)
boms_by_product = self.env['mrp.bom'].with_context(active_test=True)._bom_find(productions.product_id, picking_type=picking_type, company_id=company_id, bom_type='normal')
for production in productions:
if not production.bom_id or production.bom_id.product_tmpl_id != production.product_tmpl_id or (production.bom_id.product_id and production.bom_id.product_id != production.product_id):
bom = boms_by_product[production.product_id]
production.bom_id = bom.id or False
self.env.add_to_compute(production._fields['picking_type_id'], production)
@api.depends('bom_id')
def _compute_product_qty(self):
+62
View File
@@ -3163,3 +3163,65 @@ class TestMrpOrder(TestMrpCommon):
('warehouse_id.company_id', 'in', mo_2.company_id.ids),
], ['company_id'], load=False, limit=1)
self.assertEqual(mo_2.picking_type_id.id, picking_type_company[0]['id'])
def test_onchange_bom_ids_and_picking_type(self):
warehouse01 = self.env['stock.warehouse'].search([('company_id', '=', self.env.company.id)], limit=1)
warehouse02, warehouse03 = self.env['stock.warehouse'].create([
{'name': 'Second Warehouse', 'code': 'WH02'},
{'name': 'Third Warehouse', 'code': 'WH03'},
])
finished_product = self.env['product.product'].create({'name': 'finished product'})
bom_wh01, bom_wh02 = self.env['mrp.bom'].create([{
'product_id': finished_product.id,
'product_tmpl_id': finished_product.product_tmpl_id.id,
'product_uom_id': self.uom_unit.id,
'product_qty': 1.0,
'bom_line_ids': [(0, 0, {'product_id': self.product.id, 'product_qty': 1})],
'picking_type_id': wh.manu_type_id.id,
'sequence': wh.id,
} for wh in [warehouse01, warehouse02]])
# Prioritize BoM of WH02
bom_wh01.sequence = bom_wh02.sequence + 1
mo_form = Form(self.env['mrp.production'])
mo_form.product_id = finished_product
self.assertEqual(mo_form.bom_id, bom_wh02, 'Should select the first BoM in the list, whatever the picking type is')
self.assertEqual(mo_form.picking_type_id, warehouse02.manu_type_id)
mo_form.bom_id = bom_wh01
self.assertEqual(mo_form.picking_type_id, warehouse01.manu_type_id, 'Should be adapted because of the found BoM')
mo_form.bom_id = bom_wh02
self.assertEqual(mo_form.picking_type_id, warehouse02.manu_type_id, 'Should be adapted because of the found BoM')
mo_form.picking_type_id = warehouse01.manu_type_id
self.assertEqual(mo_form.bom_id, bom_wh02, 'Should not change')
self.assertEqual(mo_form.picking_type_id, warehouse01.manu_type_id, 'Should not change')
mo_form.picking_type_id = warehouse03.manu_type_id
mo_form.bom_id = bom_wh01
self.assertEqual(mo_form.picking_type_id, warehouse01.manu_type_id, 'Should be adapted because of the found BoM '
'(the selected picking type should be ignored)')
mo_form = Form(self.env['mrp.production'].with_context(default_picking_type_id=warehouse03.manu_type_id.id))
mo_form.product_id = finished_product
self.assertFalse(mo_form.bom_id, 'Should not find any BoM, because of the defined picking type')
self.assertEqual(mo_form.picking_type_id, warehouse03.manu_type_id)
mo_form = Form(self.env['mrp.production'].with_context(default_picking_type_id=warehouse01.manu_type_id.id))
mo_form.product_id = finished_product
self.assertEqual(mo_form.bom_id, bom_wh01, 'Should select the BoM that matches the default picking type')
self.assertEqual(mo_form.picking_type_id, warehouse01.manu_type_id, 'Should be the default one')
mo_form.bom_id = bom_wh02
self.assertEqual(mo_form.picking_type_id, warehouse01.manu_type_id, 'Should not change, because of default value')
mo_form.picking_type_id = warehouse02.manu_type_id
self.assertEqual(mo_form.bom_id, bom_wh02, 'Should not change')
self.assertEqual(mo_form.picking_type_id, warehouse02.manu_type_id, 'Should not change')
mo_form.picking_type_id = warehouse02.manu_type_id
mo_form.bom_id = bom_wh02
self.assertEqual(mo_form.picking_type_id, warehouse01.manu_type_id, 'Should be adapted because of the default value')