I ended up using python to create manufacturing order.
Here is what I do:
def assemble_product(self, product_id, part_source_location, destination_location, origin=None):
bom_description = self.get_bom_description(product_id)
manufacturing_order = self.env['mrp.production'].create([{
'product_id': product_id,
'product_qty': 1,
'product_uom_qty': 1,
'qty_produced': 1,
'product_uom_id': bom_description['product_uom_id'][0],
'bom_id': bom_description['bom_id'][0],
'origin': origin,
'move_finished_ids': [
[0, '', {
'product_id': move_finished_id[2]['product_id'][0],
'product_uom': move_finished_id[2]['product_uom'][0],
'product_uom_qty': move_finished_id[2]['product_uom_qty'],
'location_id': move_finished_id[2]['location_id'][0],
'location_dest_id': destination_location.id,
'name': move_finished_id[2]['name'],
'byproduct_id': False,
}]
for move_finished_id in bom_description['move_finished_ids'][1:]
],
'move_raw_ids': [
[0, '', {
'product_id': move_raw_id[2]['product_id'][0],
'bom_line_id': move_raw_id[2]['bom_line_id'][0],
'product_uom': move_raw_id[2]['product_uom'][0],
'product_uom_qty': move_raw_id[2]['product_uom_qty'],
'location_id': part_source_location.id,
'location_dest_id': move_raw_id[2]['location_dest_id'][0],
'name': move_raw_id[2]['name'],
}]
for move_raw_id in bom_description['move_raw_ids'][1:]
]
}])
manufacturing_order.action_confirm()
immediate_production = self.env['mrp.immediate.production'].create({
'immediate_production_line_ids': [[0, '', {
'production_id': manufacturing_order.id,
'to_immediate': True
}]]
})
immediate_production.process()
manufacturing_order.button_mark_done()
def get_bom_description(self, product_id):
onchange_res = self.env['mrp.production'].onchange(
{
'product_id': product_id,
},
'product_id',
{
'company_id': '1',
'product_id': '1',
'product_qty': '1',
'product_uom_id': '1',
'bom_id': '1',
'move_finished_ids': '1',
'move_finished_ids.product_id': '1',
'move_finished_ids.product_uom': '1',
'move_finished_ids.product_uom_qty': '1',
'move_finished_ids.location_id': '1',
'move_finished_ids.location_dest_id': '1',
'move_finished_ids.name': '',
'move_raw_ids': '1',
'move_raw_ids.product_id': '1',
'move_raw_ids.name': '',
'move_raw_ids.bom_line_id': '',
'move_raw_ids.location_id': '1',
'move_raw_ids.location_dest_id': '1',
'move_raw_ids.product_uom_qty': '1',
'move_raw_ids.product_uom': '1',
}
)
return onchange_res['value']
def assemble_product_with_serial_number(self, product_id, serial_number, part_source_location, destination_location, origin=None):
if not serial_number:
raise UserError('non-empty serial_number must be provided')
_logger.info(f'Assembling: {serial_number}')
lot_name = serial_number
existing_lot = self.env['stock.production.lot'].search([('name', '=', lot_name)], limit=1)
if existing_lot and existing_lot.product_qty > 0:
raise UserError(f'Device with serial number {lot_name} already exists')
lot = existing_lot or self.env['stock.production.lot'].create({
'product_id': product_id,
'name': lot_name,
'company_id': self.env.company.id
})
bom_description = self.get_bom_description(product_id)
manufacturing_order = self.env['mrp.production'].create([{
'product_id': product_id,
'product_qty': 1,
'product_uom_qty': 1,
'qty_produced': 1,
'product_uom_id': bom_description['product_uom_id'][0],
'bom_id': bom_description['bom_id'][0],
'origin': origin,
'move_finished_ids': [
[0, '', {
'product_id': move_finished_id[2]['product_id'][0],
'product_uom': move_finished_id[2]['product_uom'][0],
'product_uom_qty': move_finished_id[2]['product_uom_qty'],
'location_id': move_finished_id[2]['location_id'][0],
'location_dest_id': destination_location.id,
'name': move_finished_id[2]['name'],
'byproduct_id': False,
}]
for move_finished_id in bom_description['move_finished_ids'][1:]
],
'move_raw_ids': [
[0, '', {
'product_id': move_raw_id[2]['product_id'][0],
'bom_line_id': move_raw_id[2]['bom_line_id'][0],
'product_uom': move_raw_id[2]['product_uom'][0],
'product_uom_qty': move_raw_id[2]['product_uom_qty'],
'location_id': part_source_location.id,
'location_dest_id': move_raw_id[2]['location_dest_id'][0],
'name': move_raw_id[2]['name'],
}]
for move_raw_id in bom_description['move_raw_ids'][1:]
]
}])
manufacturing_order.action_confirm()
manufacturing_order.update({'lot_producing_id': lot.id})
immediate_production = self.env['mrp.immediate.production'].create({
'immediate_production_line_ids': [[0, '', {
'production_id': manufacturing_order.id,
'to_immediate': True
}]]
})
immediate_production.process()
manufacturing_order.button_mark_done()
_logger.info(f'Completed Manufacturing Order {manufacturing_order.name}')
return self.env['stock.production.lot'].browse(lot.id)
Same thing can be done using API. The important part for me was that I needed to call [mrp.production].onchange to get information about all components from the bom and then pass them in as move_finished_ids and move_raw_ids.
(edit: added example for assembling a product with serial number)
Hey there, did you work this out? I am facing the same issue. I can create the MO but cannot proceed as it has no components, I believe the stock.move has something to do with it. as this line is in mrp_production.py
move_raw_ids = fields.One2many(
'stock.move', 'raw_material_production_id', 'Components',
copy=True, states={'done': [('readonly', True)], 'cancel': [('readonly', True)]},
domain=[('scrapped', '=', False)])
I ended up using python to create manufacturing order.
Here is what I do:
```
bom_description = self.get_bom_description(product_id)
manufacturing_order = self.env['mrp.production'].create([{
'product_id': product_id,
'product_qty': 1,
'product_uom_qty': 1,
'qty_produced': 1,
'product_uom_id': bom_description['product_uom_id'][0],
'bom_id': bom_description['bom_id'][0],
'origin': origin,
'move_finished_ids': [
[0, '', {
'product_id': move_finished_id[2]['product_id'][0],
'product_uom': move_finished_id[2]['product_uom'][0],
'product_uom_qty': move_finished_id[2]['product_uom_qty'],
'location_id': move_finished_id[2]['location_id'][0],
'location_dest_id': destination_location.id,
'name': move_finished_id[2]['name'],
'byproduct_id': False,
}]
for move_finished_id in bom_description['move_finished_ids'][1:]
],
'move_raw_ids': [
[0, '', {
'product_id': move_raw_id[2]['product_id'][0],
'bom_line_id': move_raw_id[2]['bom_line_id'][0],
'product_uom': move_raw_id[2]['product_uom'][0],
'product_uom_qty': move_raw_id[2]['product_uom_qty'],
'location_id': part_source_location.id,
'location_dest_id': move_raw_id[2]['location_dest_id'][0],
'name': move_raw_id[2]['name'],
}]
for move_raw_id in bom_description['move_raw_ids'][1:]
]
}])
manufacturing_order.action_confirm()
manufacturing_order.update({'lot_producing_id': lot.id})
immediate_production = self.env['mrp.immediate.production'].create({
'immediate_production_line_ids': [[0, '', {
'production_id': manufacturing_order.id,
'to_immediate': True
}]]
})
immediate_production.process()
manufacturing_order.button_mark_done()
def get_bom_description(self, product_id):
onchange_res = self.env['mrp.production'].onchange(
{
'product_id': product_id,
},
'product_id',
{
'company_id': '1',
'product_id': '1',
'product_qty': '1',
'product_uom_id': '1',
'bom_id': '1',
'move_finished_ids': '1',
'move_finished_ids.product_id': '1',
'move_finished_ids.product_uom': '1',
'move_finished_ids.product_uom_qty': '1',
'move_finished_ids.location_id': '1',
'move_finished_ids.location_dest_id': '1',
'move_finished_ids.name': '',
'move_raw_ids': '1',
'move_raw_ids.product_id': '1',
'move_raw_ids.name': '',
'move_raw_ids.bom_line_id': '',
'move_raw_ids.location_id': '1',
'move_raw_ids.location_dest_id': '1',
'move_raw_ids.product_uom_qty': '1',
'move_raw_ids.product_uom': '1',
}
)
return onchange_res['value']
```
Same thing can be done using API. The important part for me was that I needed to call [mrp.production].onchange to get information about all components from the bom and then pass them in as move_finished_ids and move_raw_ids.