Files
test/mrp_workorder/tests/test_workorder.py
2023-04-14 17:42:23 +08:00

1537 lines
78 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.mrp.tests import common
from odoo.tests import Form
from odoo.exceptions import UserError
class TestWorkOrder(common.TestMrpCommon):
@classmethod
def setUpClass(cls):
super(TestWorkOrder, cls).setUpClass()
# Products and lots
cls.submarine_pod = cls.env['product.product'].create({
'name': 'Submarine pod',
'type': 'product',
'tracking': 'serial'})
cls.sp1 = cls.env['stock.lot'].create({
'product_id': cls.submarine_pod.id,
'name': 'sp1',
'company_id': cls.env.company.id,
})
cls.sp2 = cls.env['stock.lot'].create({
'product_id': cls.submarine_pod.id,
'name': 'sp2',
'company_id': cls.env.company.id,
})
cls.sp3 = cls.env['stock.lot'].create({
'product_id': cls.submarine_pod.id,
'name': 'sp3',
'company_id': cls.env.company.id,
})
cls.elon_musk = cls.env['product.product'].create({
'name': 'Elon Musk',
'type': 'product',
'tracking': 'serial'})
cls.elon1 = cls.env['stock.lot'].create({
'product_id': cls.elon_musk.id,
'name': 'elon1',
'company_id': cls.env.company.id,
})
cls.elon2 = cls.env['stock.lot'].create({
'product_id': cls.elon_musk.id,
'name': 'elon2',
'company_id': cls.env.company.id,
})
cls.elon3 = cls.env['stock.lot'].create({
'product_id': cls.elon_musk.id,
'name': 'elon3',
'company_id': cls.env.company.id,
})
cls.metal_cylinder = cls.env['product.product'].create({
'name': 'Metal cylinder',
'type': 'product',
'tracking': 'lot'})
cls.mc1 = cls.env['stock.lot'].create({
'product_id': cls.metal_cylinder.id,
'name': 'mc1',
'company_id': cls.env.company.id,
})
cls.trapped_child = cls.env['product.product'].create({
'name': 'Trapped child',
'type': 'product',
'tracking': 'none'})
# Bill of material
cls.bom_submarine = cls.env['mrp.bom'].create({
'product_tmpl_id': cls.submarine_pod.product_tmpl_id.id,
'product_qty': 1.0,
'operation_ids': [
(0, 0, {'name': 'Cutting Machine', 'workcenter_id': cls.workcenter_1.id, 'time_cycle': 12, 'sequence': 1}),
(0, 0, {'name': 'Weld Machine', 'workcenter_id': cls.workcenter_1.id, 'time_cycle': 18, 'sequence': 2}),
]})
cls.env['mrp.bom.line'].create({
'product_id': cls.elon_musk.id,
'product_qty': 1.0,
'bom_id': cls.bom_submarine.id,
'operation_id': cls.bom_submarine.operation_ids[1].id})
cls.env['mrp.bom.line'].create({
'product_id': cls.trapped_child.id,
'product_qty': 12.0,
'bom_id': cls.bom_submarine.id})
cls.env['mrp.bom.line'].create({
'product_id': cls.metal_cylinder.id,
'product_qty': 2.0,
'bom_id': cls.bom_submarine.id,
'operation_id': cls.bom_submarine.operation_ids[0].id})
cls.operation_4 = cls.env['mrp.routing.workcenter'].create({
'name': 'Rescue operation',
'workcenter_id': cls.workcenter_1.id,
'bom_id': cls.bom_submarine.id,
'time_cycle': 13,
'sequence': 2})
#cls.mrp_routing_0 = cls.env['mrp.routing'].create({
# 'name': 'Primary Assembly',
#})
#cls.mrp_routing_1 = cls.env['mrp.routing'].create({
# 'name': 'Secondary Assembly',
#})
cls.mrp_workcenter_1 = cls.env['mrp.workcenter'].create({
'name': 'Drill Station 1',
'resource_calendar_id': cls.env.ref('resource.resource_calendar_std').id,
})
cls.mrp_workcenter_3 = cls.env['mrp.workcenter'].create({
'name': 'Assembly Line 1',
'resource_calendar_id': cls.env.ref('resource.resource_calendar_std').id,
})
# --------------
# .mrp_routing_0
# --------------
# cls.mrp_routing_workcenter_0 = cls.env['mrp.routing.workcenter'].create({
# #'routing_id': cls.mrp_routing_0.id,
# 'workcenter_id': cls.mrp_workcenter_3.id,
# 'name': 'Manual Assembly',
# 'time_cycle': 60,
# })
#
# # -------------
# # mpr_routing_1
# # -------------
# cls.mrp_routing_workcenter_1 = cls.env['mrp.routing.workcenter'].create({
# #'routing_id': cls.mrp_routing_1.id,
# 'workcenter_id': cls.mrp_workcenter_3.id,
# 'name': 'Long time assembly',
# 'time_cycle': 180,
# 'sequence': 15,
# })
# cls.mrp_routing_workcenter_3 = cls.env['mrp.routing.workcenter'].create({
# #'routing_id': cls.mrp_routing_1.id,
# 'workcenter_id': cls.mrp_workcenter_3.id,
# 'name': 'Testing',
# 'time_cycle': 60,
# 'sequence': 10,
# })
# cls.mrp_routing_workcenter_4 = cls.env['mrp.routing.workcenter'].create({
# #'routing_id': cls.mrp_routing_1.id,
# 'workcenter_id': cls.mrp_workcenter_1.id,
# 'name': 'Packing',
# 'time_cycle': 30,
# 'sequence': 5,
# })
# Update quantities
cls.location_1 = cls.env.ref('stock.stock_location_stock')
Quant = cls.env['stock.quant']
Quant._update_available_quantity(cls.elon_musk, cls.location_1, 1.0, lot_id=cls.elon1)
Quant._update_available_quantity(cls.elon_musk, cls.location_1, 1.0, lot_id=cls.elon2)
Quant._update_available_quantity(cls.elon_musk, cls.location_1, 1.0, lot_id=cls.elon3)
Quant._update_available_quantity(cls.metal_cylinder, cls.location_1, 6.0, lot_id=cls.mc1)
Quant._update_available_quantity(cls.trapped_child, cls.location_1, 36.0)
def test_assign_1(self):
unit = self.ref("uom.product_uom_unit")
self.stock_location = self.env.ref('stock.stock_location_stock')
custom_laptop = self.env['product.product'].create({
'name': 'Drawer',
'type': 'product',
'uom_id': unit,
'uom_po_id': unit,
})
custom_laptop.tracking = 'none'
product_charger = self.env['product.product'].create({
'name': 'Charger',
'type': 'product',
'tracking': 'lot',
'uom_id': unit,
'uom_po_id': unit})
product_keybord = self.env['product.product'].create({
'name': 'Usb Keybord',
'type': 'product',
'uom_id': unit,
'uom_po_id': unit})
bom_custom_laptop = self.env['mrp.bom'].create({
'product_tmpl_id': custom_laptop.product_tmpl_id.id,
'product_qty': 1,
'product_uom_id': unit,
#'routing_id': self.mrp_routing_0.id,
# inlined mrp_routing0
'bom_line_ids': [(0, 0, {
'product_id': product_charger.id,
'product_qty': 1,
'product_uom_id': unit
}), (0, 0, {
'product_id': product_keybord.id,
'product_qty': 1,
'product_uom_id': unit
})],
'operation_ids': [(0, 0, {
'workcenter_id': self.mrp_workcenter_3.id,
'name': 'Manual Assembly',
'time_cycle': 60,
})]
})
production_form = Form(self.env['mrp.production'])
production_form.product_id = custom_laptop
production_form.bom_id = bom_custom_laptop
production_form.product_qty = 2
production = production_form.save()
production.action_confirm()
production.button_plan()
workorder = production.workorder_ids
self.assertTrue(workorder)
self.env['stock.quant']._update_available_quantity(product_charger, self.stock_location, 5)
self.env['stock.quant']._update_available_quantity(product_keybord, self.stock_location, 5)
production.action_assign()
def test_flexible_consumption_1b(self):
""" Production with a strict consumption
Check that consuming a non tracked product more than planned triggers an error"""
self.env['quality.point'].create({
'product_ids': [(4, self.submarine_pod.id)],
'picking_type_ids': [(4, self.env['stock.picking.type'].search([('code', '=', 'mrp_operation')], limit=1).id)],
'operation_id': self.bom_submarine.operation_ids[0].id,
'test_type_id': self.env.ref('mrp_workorder.test_type_register_consumed_materials').id,
'component_id': self.trapped_child.id,
})
self.submarine_pod.tracking = 'lot'
self.bom_submarine.bom_line_ids.filtered(lambda line: line.product_id == self.trapped_child).operation_id = self.bom_submarine.operation_ids[0]
mo_form = Form(self.env['mrp.production'])
mo_form.product_id = self.submarine_pod
mo_form.bom_id = self.bom_submarine
mo_form.product_qty = 2
mo = mo_form.save()
mo.action_confirm()
mo.action_assign()
mo.button_plan()
wo = mo.workorder_ids.sorted()[0]
wo.button_start()
wo_form = Form(wo, view='mrp_workorder.mrp_workorder_view_form_tablet')
wo_form.qty_producing = 2
wo = wo_form.save()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.component_id, self.trapped_child, 'The suggested component is wrong')
self.assertEqual(qc_form.qty_done, 24, 'The suggested component qty_done is wrong')
self.assertEqual(qc_form.component_remaining_qty, 24, 'The remaining quantity is wrong')
# check the onchange on qty_producing is working
qc = qc_form.save()
wo_form = Form(wo, view='mrp_workorder.mrp_workorder_view_form_tablet')
wo_form.qty_producing = 1
wo = wo_form.save()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.qty_done, 12, 'The quantity done is wrong')
self.assertEqual(qc_form.component_remaining_qty, 12, 'The remaining quantity is wrong')
qc_form.save()
wo_form = Form(wo, view='mrp_workorder.mrp_workorder_view_form_tablet')
wo_form.qty_producing = 2
wo = wo_form.save()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.qty_done, 24, 'The quantity done is wrong')
self.assertEqual(qc_form.component_remaining_qty, 24, 'The remaining quantity is wrong')
qc_form.qty_done = 12
qc = qc_form.save()
qc.action_continue()
# Check the remaining quantity is well computed
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.qty_done, 12, 'The suggested component qty_done is wrong')
self.assertEqual(qc_form.component_remaining_qty, 12, 'The remaining quantity is wrong')
def test_flexible_consumption_1c(self):
""" Production with a strict consumption
Check that consuming the right amount of component doesn't trigger any error"""
self.env['quality.point'].create({
'product_ids': [(4, self.submarine_pod.id)],
'picking_type_ids': [(4, self.env['stock.picking.type'].search([('code', '=', 'mrp_operation')], limit=1).id)],
'operation_id': self.bom_submarine.operation_ids[0].id,
'test_type_id': self.env.ref('mrp_workorder.test_type_register_consumed_materials').id,
'component_id': self.trapped_child.id,
})
self.bom_submarine.bom_line_ids.filtered(lambda line: line.product_id == self.trapped_child).operation_id = self.bom_submarine.operation_ids[0]
mo_form = Form(self.env['mrp.production'])
mo_form.product_id = self.submarine_pod
mo_form.bom_id = self.bom_submarine
mo_form.product_qty = 1
mo = mo_form.save()
mo.action_confirm()
mo.action_assign()
mo.button_plan()
sorted_workorder_ids = mo.workorder_ids.sorted()
wo = sorted_workorder_ids[0]
wo.button_start()
wo_form = Form(wo, view='mrp_workorder.mrp_workorder_view_form_tablet')
self.assertEqual(wo_form.qty_producing, 1)
wo_form.finished_lot_id = self.sp1
wo = wo_form.save()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.qty_done, 12, 'The suggested component qty_done is wrong')
qc_form.qty_done = 6
qc = qc_form.save()
qc.action_continue()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.component_id, self.trapped_child, 'The suggested component is wrong')
self.assertEqual(qc_form.qty_done, 6, 'The suggested component qty_done is wrong')
qc = qc_form.save()
qc._next()
wo_form = Form(wo, view='mrp_workorder.mrp_workorder_view_form_tablet')
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.qty_done, 2, 'The suggested component qty_done is wrong')
self.assertEqual(qc_form.lot_id, self.mc1, 'The suggested lot is wrong')
qc_form.qty_done = 1
qc = qc_form.save()
qc.action_continue()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.component_id, self.metal_cylinder, 'The suggested component is wrong')
self.assertEqual(qc_form.qty_done, 1, 'The suggested component qty_done is wrong')
self.assertEqual(qc_form.lot_id, self.mc1, 'The suggested lot is wrong')
qc = qc_form.save()
qc._next()
wo.do_finish()
wo = sorted_workorder_ids[1]
wo.button_start()
wo_form = Form(wo, view='mrp_workorder.mrp_workorder_view_form_tablet')
self.assertEqual(wo_form.finished_lot_id, self.sp1, 'The suggested final product is wrong')
wo = wo_form.save()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.qty_done, 1, 'The suggested qty_done should be one as the component is a serial number')
# try to write on readonly field
with self.assertRaises(AssertionError):
qc_form.qty_done = 2
self.assertEqual(qc_form.lot_id, self.elon1, 'The suggested lot is wrong')
qc = qc_form.save()
qc._next()
wo.do_finish()
wo = sorted_workorder_ids[2]
wo.button_start()
self.assertEqual(wo.finished_lot_id, self.sp1, 'The suggested final product is wrong')
wo.do_finish()
# Verify the reserved quantity has been split correctly
self.assertEqual(mo.move_raw_ids.move_line_ids[1].reserved_uom_qty, 6.0, 'The reserved quantity is wrong')
self.assertEqual(mo.move_raw_ids.move_line_ids[2].reserved_uom_qty, 6.0, 'The reserved quantity is wrong')
self.assertEqual(mo.move_raw_ids.move_line_ids[3].reserved_uom_qty, 1.0, 'The reserved quantity is wrong')
self.assertEqual(mo.move_raw_ids.move_line_ids[4].reserved_uom_qty, 1.0, 'The reserved quantity is wrong')
mo.button_mark_done()
self.assertEqual(mo.state, 'done', 'Final state of the MO should be "done"')
def test_flexible_consumption_2(self):
""" Production with a flexible consumption
Check that consuming different quantities than planned doensn't trigger
any error"""
self.bom_submarine.consumption = 'flexible'
mo_form = Form(self.env['mrp.production'])
mo_form.product_id = self.submarine_pod
mo_form.bom_id = self.bom_submarine
mo_form.product_qty = 1
mo = mo_form.save()
mo.action_confirm()
mo.action_assign()
mo.button_plan()
sorted_workorder_ids = mo.workorder_ids.sorted()
wo = sorted_workorder_ids[0]
wo.button_start()
wo.finished_lot_id = self.sp1
self.assertEqual(wo.current_quality_check_id.lot_id, self.mc1, 'The suggested lot is wrong')
wo.current_quality_check_id.qty_done = 1
wo.current_quality_check_id._next()
wo.do_finish()
wo = sorted_workorder_ids[1]
wo.button_start()
self.assertEqual(wo.finished_lot_id, self.sp1, 'The suggested final product is wrong')
self.assertEqual(wo.current_quality_check_id.lot_id, self.elon1, 'The suggested lot is wrong')
wo.current_quality_check_id.action_continue()
wo.current_quality_check_id.lot_id = self.elon2
wo.current_quality_check_id._next()
wo.do_finish()
wo = sorted_workorder_ids[2]
wo.button_start()
self.assertEqual(wo.finished_lot_id, self.sp1, 'The suggested final product is wrong')
wo.do_finish()
mo.button_mark_done()
move_1 = mo.move_raw_ids.filtered(lambda move: move.product_id == self.metal_cylinder and move.state == 'done')
self.assertEqual(sum(move_1.mapped('quantity_done')), 1, 'Only one cylinder was consumed')
move_2 = mo.move_raw_ids.filtered(lambda move: move.product_id == self.elon_musk and move.state == 'done')
self.assertEqual(sum(move_2.mapped('quantity_done')), 2, '2 Elon Musk was consumed')
move_3 = mo.move_raw_ids.filtered(lambda move: move.product_id == self.trapped_child and move.state == 'done')
self.assertEqual(sum(move_3.mapped('quantity_done')), 12, '12 child was consumed')
self.assertEqual(mo.state, 'done', 'Final state of the MO should be "done"')
def test_workorder_reservation_1(self):
# Test multiple final lots management
mrp_order_form = Form(self.env['mrp.production'])
mrp_order_form.product_id = self.submarine_pod
mrp_order_form.product_qty = 1
production = mrp_order_form.save()
production.action_confirm()
production.action_assign()
production.button_plan()
sorted_workorder_ids = production.workorder_ids.sorted()
wo = sorted_workorder_ids[0]
wo.button_start()
wo_form = Form(wo, view='mrp_workorder.mrp_workorder_view_form_tablet')
wo_form.finished_lot_id = self.sp1
wo = wo_form.save()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.lot_id, self.mc1, "component lot should be prefilled")
self.assertEqual(qc_form.qty_done, 2, "component quantity should be prefilled")
qc = qc_form.save()
qc._next()
wo.record_production()
wo = sorted_workorder_ids[1]
wo.button_start()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.lot_id, self.elon1, "component lot should be prefilled")
self.assertEqual(qc_form.qty_done, 1, "component quantity should be prefilled")
qc = qc_form.save()
qc._next()
wo.record_production()
wo = sorted_workorder_ids[2]
wo.button_start()
wo_form = Form(wo, view='mrp_workorder.mrp_workorder_view_form_tablet')
self.assertEqual(wo_form.finished_lot_id, self.sp1, "final lot should be prefilled")
wo = wo_form.save()
wo.do_finish()
production.button_mark_done()
move_elon = production.move_raw_ids.filtered(lambda move: move.product_id == self.elon_musk)
self.assertEqual(move_elon.state, 'done', 'Move should be done')
self.assertEqual(move_elon.quantity_done, 1, 'Consumed quantity should be 2')
self.assertEqual(len(move_elon.move_line_ids), 1, 'their should be 2 move lines')
self.assertEqual(move_elon.move_line_ids.lot_id, self.elon1, 'Wrong serial number used')
move_cylinder = production.move_raw_ids.filtered(lambda move: move.product_id == self.metal_cylinder)
self.assertEqual(move_cylinder.state, 'done', 'Move should be done')
self.assertEqual(move_cylinder.quantity_done, 2, 'Consumed quantity should be 4')
move_child = production.move_raw_ids.filtered(lambda move: move.product_id == self.trapped_child)
self.assertEqual(move_child.state, 'done', 'Move should be done')
self.assertEqual(move_child.quantity_done, 12, 'Consumed quantity should be 24')
def test_workorder_reservation_2(self):
# Test multiple final product tracked by sn and all consumption in the same
# workorder.
# Also test assignment after workorder planning
self.bom_submarine.bom_line_ids.write({
'operation_id': False,
})
self.bom_submarine.operation_ids = False
self.bom_submarine.write({
'operation_ids': [(0, 0, {
'workcenter_id': self.mrp_workcenter_3.id,
'name': 'Manual Assembly',
'time_cycle': 60,
})]
})
mrp_order_form = Form(self.env['mrp.production'])
mrp_order_form.product_id = self.submarine_pod
mrp_order_form.product_qty = 2
production = mrp_order_form.save()
production.action_confirm()
production.button_plan()
production.action_assign()
production.workorder_ids.button_start()
wo_form = Form(production.workorder_ids, view='mrp_workorder.mrp_workorder_view_form_tablet')
wo_form.finished_lot_id = self.sp1
self.assertEqual(wo_form.qty_producing, 1, "Quantity to produce should prefilled with 1 (serial tracked product)")
wo = wo_form.save()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.lot_id, self.elon1, "component lot should be prefilled")
self.assertEqual(qc_form.qty_done, 1, "component quantity should be 1 as final product is tracked")
self.assertEqual(qc_form.component_remaining_qty, 1, "It needs 2 component")
qc = qc_form.save()
wo.current_quality_check_id._next()
wo_form = Form(production.workorder_ids, view='mrp_workorder.mrp_workorder_view_form_tablet')
qc_form = Form(production.workorder_ids.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.lot_id, self.mc1, "qcrkorder should consume the second product")
self.assertEqual(qc_form.qty_done, 2, "Quantity to consume should prefilled with 2")
self.assertEqual(qc_form.component_id, self.metal_cylinder, "qcrkorder should be consume the second product")
qc = qc_form.save()
wo.current_quality_check_id._next()
action = wo.record_production()
wo_form = Form(self.env['mrp.workorder'].browse(action['res_id']), view='mrp_workorder.mrp_workorder_view_form_tablet')
wo_form.finished_lot_id = self.sp2
self.assertEqual(wo_form.qty_producing, 1, "Quantity to produce should prefilled with 1 (serial tracked product)")
wo = wo_form.save()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.lot_id, self.elon2, "component lot should be prefilled")
self.assertEqual(qc_form.qty_done, 1, "component quantity should be 1 as final product is tracked")
qc = qc_form.save()
self.assertEqual(wo.qty_production, 1, "Quantity to produce should be 2")
qc._next()
qc_form = Form(self.env['mrp.workorder'].browse(action['res_id']).current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.lot_id, self.mc1, "qcrkorder should consume the second product")
self.assertEqual(qc_form.qty_done, 2, "Quantity to consume should prefilled with 2")
self.assertEqual(qc_form.component_id, self.metal_cylinder, "qcrkorder should be consume the second product")
qc = qc_form.save()
qc._next()
wo.do_finish()
productions = production.procurement_group_id.mrp_production_ids
productions.button_mark_done()
move_elon = productions.move_raw_ids.filtered(lambda move: move.product_id == self.elon_musk)
self.assertEqual(move_elon.mapped('state'), ['done'] * 2, 'Move should be done')
self.assertEqual(sum(move_elon.mapped('quantity_done')), 2, 'Consumed quantity should be 2')
self.assertEqual(len(move_elon.move_line_ids), 2, 'their should be 2 move lines')
self.assertEqual(move_elon.move_line_ids.mapped('lot_id'), self.elon1 | self.elon2, 'Wrong serial numbers used')
move_cylinder = productions.move_raw_ids.filtered(lambda move: move.product_id == self.metal_cylinder)
self.assertEqual(move_cylinder.mapped('state'), ['done'] * 2, 'Move should be done')
self.assertEqual(sum(move_cylinder.mapped('quantity_done')), 4, 'Consumed quantity should be 4')
move_child = productions.move_raw_ids.filtered(lambda move: move.product_id == self.trapped_child)
self.assertEqual(move_child.mapped('state'), ['done'] * 2, 'Move should be done')
self.assertEqual(sum(move_child.mapped('quantity_done')), 24, 'Consumed quantity should be 24')
def test_workorder_reservation_3(self):
""" Test quantities suggestions make the whole production in only 1 workorder """
self.bom_submarine.operation_ids = False
self.bom_submarine.write({
'operation_ids': [(0, 0, {
'workcenter_id': self.workcenter_1.id,
'name': 'Manual Assembly',
'time_cycle': 60,
'sequence': 5,
})],
})
self.bom_submarine.bom_line_ids.write({'operation_id': self.bom_submarine.operation_ids.id})
self.bom_submarine.bom_line_ids.filtered(lambda line: line.product_id == self.elon_musk).product_qty = 2
self.bom_submarine.bom_line_ids.filtered(lambda line: line.product_id == self.metal_cylinder).product_qty = 3
self.bom_submarine.bom_line_ids.filtered(lambda line: line.product_id == self.trapped_child).unlink()
self.mc2 = self.env['stock.lot'].create({
'product_id': self.metal_cylinder.id,
'name': 'mc2',
'company_id': self.env.company.id,
})
self.env['stock.quant']._update_available_quantity(self.metal_cylinder, self.location_1, -5.0, lot_id=self.mc1)
self.env['stock.quant']._update_available_quantity(self.metal_cylinder, self.location_1, 2.0, lot_id=self.mc2)
mrp_order_form = Form(self.env['mrp.production'])
self.submarine_pod.tracking = 'none'
mrp_order_form.product_id = self.submarine_pod
mrp_order_form.product_qty = 1
production = mrp_order_form.save()
production.action_confirm()
production.action_assign()
production.button_plan()
self.assertEqual(len(production.workorder_ids), 1, "wrong number of workorders")
self.assertEqual(production.workorder_ids[0].state, 'ready', "workorder state should be 'ready'")
production.workorder_ids[0].button_start()
wo_form = Form(production.workorder_ids[0], view='mrp_workorder.mrp_workorder_view_form_tablet')
self.assertEqual(wo_form.qty_producing, 0, "Wrong quantity to produce")
wo_form.qty_producing = 1
wo = wo_form.save()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.component_id, self.elon_musk, "The component should be changed")
self.assertEqual(qc_form.lot_id, self.elon1, "The component should be changed")
self.assertEqual(qc_form.qty_done, 1, "Wrong suggested quantity")
qc = qc_form.save()
qc.action_continue()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.lot_id, self.elon2, "The component should be changed")
self.assertEqual(qc_form.qty_done, 1, "Wrong suggested quantity")
qc = qc_form.save()
qc._next()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.component_id, self.metal_cylinder, "The component should be changed")
self.assertEqual(qc_form.lot_id, self.mc1, "wrong suggested lot")
self.assertEqual(qc_form.qty_done, 1, "wrong suggested quantity")
qc = qc_form.save()
qc.action_continue()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.lot_id, self.mc2, "Wrong suggested lot")
self.assertEqual(qc_form.qty_done, 2, "Wrong suggested quantity")
qc = qc_form.save()
qc._next()
wo.do_finish()
production.button_mark_done()
move_elon = production.move_raw_ids.filtered(lambda move: move.product_id == self.elon_musk)
self.assertEqual(move_elon.state, 'done', 'Move should be done')
self.assertEqual(move_elon.quantity_done, 2, 'Consumed quantity should be 2')
self.assertEqual(len(move_elon.move_line_ids), 2, 'their should be 2 move lines')
self.assertEqual(move_elon.move_line_ids.mapped('lot_id'), self.elon1 | self.elon2, 'Wrong serial numbers used')
move_cylinder = production.move_raw_ids.filtered(lambda move: move.product_id == self.metal_cylinder)
self.assertEqual(move_cylinder.state, 'done', 'Move should be done')
self.assertEqual(move_cylinder.quantity_done, 3, 'Consumed quantity should be 4')
self.assertEqual(move_cylinder.move_line_ids.mapped('lot_id'), self.mc1 | self.mc2, 'Wrong serial numbers used')
def test_workorder_1(self):
# get the computer sc234 demo data
prod = self.submarine_pod
bom = self.bom_submarine
mrp_order_form = Form(self.env['mrp.production'])
mrp_order_form.product_id = self.submarine_pod
mrp_order_form.product_qty = 1
production = mrp_order_form.save()
# plan the work orders
production.button_plan()
def test_workorder_2(self):
# Test multiple final lots management
mrp_order_form = Form(self.env['mrp.production'])
mrp_order_form.product_id = self.submarine_pod
mrp_order_form.product_qty = 3
production = mrp_order_form.save()
production.action_confirm()
production.button_plan()
sorted_workorder_ids = production.workorder_ids.sorted()
self.assertEqual(len(production.workorder_ids), 3, "wrong number of workorders")
self.assertEqual(sorted_workorder_ids[0].state, 'ready', "workorder state should be 'ready'")
self.assertEqual(sorted_workorder_ids[1].state, 'pending', "workorder state should be 'pending'")
sorted_workorder_ids[0].button_start()
wo_form = Form(sorted_workorder_ids[0], view='mrp_workorder.mrp_workorder_view_form_tablet')
self.assertEqual(wo_form.finished_lot_id.id, False, "final lot should be empty")
self.assertEqual(wo_form.qty_producing, 1, "Wrong quantity to produce (serial tracked)")
wo_form.finished_lot_id = self.sp1
wo = wo_form.save()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.qty_done, 2, "Wrong quantity to consume")
qc_form.lot_id = self.mc1
qc = qc_form.save()
qc._next()
action = wo.record_production()
wo_form = Form(self.env['mrp.workorder'].browse(action['res_id']), view='mrp_workorder.mrp_workorder_view_form_tablet')
wo_form.finished_lot_id = self.sp2
self.assertEqual(wo_form.qty_producing, 1, "Wrong quantity to produce (serial tracked)")
wo = wo_form.save()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.qty_done, 2, "Wrong quantity to consume")
qc_form.lot_id = self.mc1
qc = qc_form.save()
qc._next()
action = wo.record_production()
wo_form = Form(self.env['mrp.workorder'].browse(action['res_id']), view='mrp_workorder.mrp_workorder_view_form_tablet')
wo_form.finished_lot_id = self.sp3
wo = wo_form.save()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.qty_done, 2, "Wrong quantity to consume")
qc_form.lot_id = self.mc1
qc = qc_form.save()
qc._next()
wo.do_finish()
sorted_workorder_ids_2 = production.procurement_group_id.mrp_production_ids[1].workorder_ids.sorted()
sorted_workorder_ids_3 = production.procurement_group_id.mrp_production_ids[2].workorder_ids.sorted()
sorted_workorder_ids[1].button_start()
wo_form = Form(sorted_workorder_ids[1], view='mrp_workorder.mrp_workorder_view_form_tablet')
self.assertEqual(wo_form.finished_lot_id, self.sp1, "final lot should be prefilled")
wo = wo_form.save()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
qc_form.lot_id = self.elon1
qc = qc_form.save()
qc._next()
wo.record_production()
sorted_workorder_ids_2[1].button_start()
wo_form = Form(sorted_workorder_ids_2[1], view='mrp_workorder.mrp_workorder_view_form_tablet')
self.assertEqual(wo_form.finished_lot_id, self.sp2, "final lot should be prefilled")
wo = wo_form.save()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
qc_form.lot_id = self.elon2
qc = qc_form.save()
qc._next()
wo.record_production()
sorted_workorder_ids_3[1].button_start()
wo_form = Form(sorted_workorder_ids_3[1], view='mrp_workorder.mrp_workorder_view_form_tablet')
self.assertEqual(wo_form.finished_lot_id, self.sp3, "final lot should be prefilled")
wo = wo_form.save()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
qc_form.lot_id = self.elon3
qc = qc_form.save()
qc._next()
wo.do_finish()
sorted_workorder_ids[2].button_start()
wo_form = Form(sorted_workorder_ids[2], view='mrp_workorder.mrp_workorder_view_form_tablet')
self.assertEqual(wo_form.finished_lot_id, self.sp1, "final lot should be prefilled")
self.assertEqual(wo_form.qty_producing, 1, "Wrong quantity to produce (serial tracked)")
wo = wo_form.save()
wo.record_production()
sorted_workorder_ids_2[2].button_start()
wo_form = Form(sorted_workorder_ids_2[2], view='mrp_workorder.mrp_workorder_view_form_tablet')
self.assertEqual(wo_form.finished_lot_id, self.sp2, "final lot should be prefilled")
self.assertEqual(wo_form.qty_producing, 1, "Wrong quantity to produce (serial tracked)")
wo = wo_form.save()
wo.record_production()
sorted_workorder_ids_3[2].button_start()
wo_form = Form(sorted_workorder_ids_3[2], view='mrp_workorder.mrp_workorder_view_form_tablet')
self.assertEqual(wo_form.finished_lot_id, self.sp3, "final lot should be prefilled")
self.assertEqual(wo_form.qty_producing, 1, "Wrong quantity to produce (serial tracked)")
wo = wo_form.save()
wo.do_finish()
productions = production.procurement_group_id.mrp_production_ids
productions.button_mark_done()
move_elon = productions.move_raw_ids.filtered(lambda move: move.product_id == self.elon_musk)
self.assertEqual(move_elon.mapped('state'), ['done'] * 3, 'Move should be done')
self.assertEqual(sum(move_elon.mapped('quantity_done')), 3, 'Consumed quantity should be 2')
self.assertEqual(len(move_elon.move_line_ids), 3, 'their should be 2 move lines')
self.assertEqual(move_elon.move_line_ids.mapped('lot_id'), self.elon1 | self.elon2 | self.elon3, 'Wrong serial numbers used')
self.assertEqual(move_elon.move_line_ids.produce_line_ids.lot_id, self.sp1 | self.sp2 | self.sp3, 'Wrong produced serial numbers')
move_cylinder = productions.move_raw_ids.filtered(lambda move: move.product_id == self.metal_cylinder)
self.assertEqual(move_cylinder.mapped('state'), ['done'] * 3, 'Move should be done')
self.assertEqual(sum(move_cylinder.mapped('quantity_done')), 6, 'Consumed quantity should be 4')
self.assertEqual(move_cylinder.move_line_ids.produce_line_ids.lot_id, self.sp1 | self.sp2 | self.sp3, 'Wrong produced serial numbers')
move_child = productions.move_raw_ids.filtered(lambda move: move.product_id == self.trapped_child)
self.assertEqual(move_child.mapped('state'), ['done'] * 3, 'Move should be done')
self.assertEqual(sum(move_child.mapped('quantity_done')), 36, 'Consumed quantity should be 24')
self.assertEqual(len(move_child.move_line_ids), 3, 'Their should be 3 move line as production was made in 3 steps')
self.assertEqual(move_child.move_line_ids.produce_line_ids.lot_id, self.sp1 | self.sp2 | self.sp3, 'Wrong produced serial numbers')
def test_workorder_3(self):
# Test multiple final lots management
# Required for `byproduct_ids` to be visible in the view
self.env.user.groups_id += self.env.ref('mrp.group_mrp_byproducts')
self.angry_british_diver = self.env['product.product'].create({
'name': 'Angry Bristish Driver',
'description': 'can stick his submarine where it hurts',
'type': 'product',
'tracking': 'serial'
})
self.abd_1 = self.env['stock.lot'].create({
'product_id': self.angry_british_diver.id,
'name': 'abd_1',
'company_id': self.env.company.id,
})
self.abd_2 = self.env['stock.lot'].create({
'product_id': self.angry_british_diver.id,
'name': 'abd_2',
'company_id': self.env.company.id,
})
self.advertising = self.env['product.product'].create({
'name': 'Advertising',
'type': 'product',
'tracking': 'lot',
})
self.advertise_1 = self.env['stock.lot'].create({
'product_id': self.advertising.id,
'name': 'Good Advertise',
'company_id': self.env.company.id,
})
self.advertise_2 = self.env['stock.lot'].create({
'product_id': self.advertising.id,
'name': 'bad Advertise',
'company_id': self.env.company.id,
})
submarine_pod_bom_form = Form(self.bom_submarine)
with submarine_pod_bom_form.byproduct_ids.new() as bp:
bp.product_id = self.angry_british_diver
bp.product_qty = 1.0
bp.operation_id = self.bom_submarine.operation_ids[1]
with submarine_pod_bom_form.byproduct_ids.new() as bp:
bp.product_id = self.advertising
bp.product_qty = 2.0
submarine_pod_bom_form.save()
mrp_order_form = Form(self.env['mrp.production'])
self.submarine_pod.tracking = 'none'
mrp_order_form.product_id = self.submarine_pod
mrp_order_form.product_qty = 2
production = mrp_order_form.save()
production.action_confirm()
production.button_plan()
sorted_workorder_ids = production.workorder_ids.sorted()
self.assertEqual(len(production.workorder_ids), 3, "wrong number of workorders")
self.assertEqual(sorted_workorder_ids[0].state, 'ready', "workorder state should be 'ready'")
self.assertEqual(sorted_workorder_ids[1].state, 'pending', "workorder state should be 'pending'")
sorted_workorder_ids[0].button_start()
wo_form = Form(sorted_workorder_ids[0], view='mrp_workorder.mrp_workorder_view_form_tablet')
self.assertEqual(wo_form.qty_producing, 0, "Wrong quantity to produce")
wo_form.qty_producing = 1
wo = wo_form.save()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
qc_form.lot_id = self.mc1
self.assertEqual(qc_form.qty_done, 2, "Wrong quantity to consume")
wo.current_quality_check_id._next()
action = wo.record_production()
wo_form = Form(self.env['mrp.workorder'].browse(action['res_id']), view='mrp_workorder.mrp_workorder_view_form_tablet')
self.assertEqual(wo_form.qty_producing, 1, "Wrong quantity remaining")
wo = wo_form.save()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.qty_done, 2, "Wrong quantity to consume")
qc_form.lot_id = self.mc1
qc = qc_form.save()
qc._next()
wo.do_finish()
sorted_workorder_ids[1].button_start()
wo_form = Form(sorted_workorder_ids[1], view='mrp_workorder.mrp_workorder_view_form_tablet')
self.assertEqual(wo_form.qty_producing, 1, "Wrong quantity to produce (serial tracked)")
wo = wo_form.save()
qc_form = Form(sorted_workorder_ids[1].current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
qc_form.lot_id = self.elon1
qc = qc_form.save()
qc._next()
# By-product management
qc_form = Form(sorted_workorder_ids[1].current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.component_id, self.angry_british_diver)
qc_form.lot_id = self.abd_1
qc = qc_form.save()
qc._next()
action = wo.record_production()
wo_form = Form(self.env['mrp.workorder'].browse(action['res_id']), view='mrp_workorder.mrp_workorder_view_form_tablet')
self.assertEqual(wo_form.qty_producing, 1, "Wrong quantity remaining")
wo = wo_form.save()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
qc_form.lot_id = self.elon2
qc = qc_form.save()
qc._next()
# By-product management
qc_form = Form(self.env['mrp.workorder'].browse(action['res_id']).current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.component_id, self.angry_british_diver)
qc_form.lot_id = self.abd_2
qc = qc_form.save()
qc._next()
wo.do_finish()
sorted_workorder_ids[2].button_start()
wo_form = Form(sorted_workorder_ids[2], view='mrp_workorder.mrp_workorder_view_form_tablet')
self.assertEqual(wo_form.qty_producing, 1, "Wrong quantity to produce (serial tracked)")
wo = wo_form.save()
qc_form = Form(sorted_workorder_ids[2].current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
qc_form.qty_done = 2.0
self.assertEqual(qc_form.component_id, self.advertising, "Wrong product")
qc_form.lot_id = self.advertise_1
qc = qc_form.save()
qc._next()
action = wo.record_production()
wo_form = Form(self.env['mrp.workorder'].browse(action['res_id']), view='mrp_workorder.mrp_workorder_view_form_tablet')
self.assertEqual(wo_form.qty_producing, 1, "Wrong quantity to produce")
wo = wo_form.save()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.component_id, self.advertising, "Wrong product")
qc_form.qty_done = 2.0
qc_form.lot_id = self.advertise_2
qc = qc_form.save()
qc._next()
wo.do_finish()
productions = production.procurement_group_id.mrp_production_ids
productions.button_mark_done()
move_elon = productions.move_raw_ids.filtered(lambda move: move.product_id == self.elon_musk)
self.assertEqual(move_elon.mapped('state'), ['done'] * 2, 'Move should be done')
self.assertEqual(sum(move_elon.mapped('quantity_done')), 2, 'Consumed quantity should be 2')
self.assertEqual(len(move_elon.move_line_ids), 2, 'their should be 2 move lines')
self.assertEqual(move_elon.move_line_ids.mapped('lot_id'), self.elon1 | self.elon2, 'Wrong serial numbers used')
move_cylinder = productions.move_raw_ids.filtered(lambda move: move.product_id == self.metal_cylinder)
self.assertEqual(move_cylinder.mapped('state'), ['done'] * 2, 'Move should be done')
self.assertEqual(sum(move_cylinder.mapped('quantity_done')), 4, 'Consumed quantity should be 4')
move_child = productions.move_raw_ids.filtered(lambda move: move.product_id == self.trapped_child)
self.assertEqual(move_child.mapped('state'), ['done'] * 2, 'Move should be done')
self.assertEqual(sum(move_child.mapped('quantity_done')), 24, 'Consumed quantity should be 24')
self.assertEqual(len(move_child.move_line_ids), 2, 'Their should be 2 move lines as their are two production')
move_byproduct_angry_british_diver = productions.move_finished_ids.filtered(lambda move: move.product_id == self.angry_british_diver)
self.assertEqual(move_byproduct_angry_british_diver.mapped('state'), ['done'] * 2, 'Move should be done')
self.assertEqual(sum(move_byproduct_angry_british_diver.mapped('quantity_done')), 2, 'Consumed quantity should be 2')
self.assertEqual(len(move_byproduct_angry_british_diver.move_line_ids), 2, 'Their should be 2 move lines')
self.assertEqual(move_byproduct_angry_british_diver.move_line_ids.mapped('lot_id'), self.abd_1 | self.abd_2, 'Wrong serial numbers used')
move_byproduct_advertising = productions.move_finished_ids.filtered(lambda move: move.product_id == self.advertising)
self.assertEqual(move_byproduct_advertising.mapped('state'), ['done'] * 2, 'Move should be done')
self.assertEqual(sum(move_byproduct_advertising.mapped('quantity_done')), 4, 'Consumed quantity should be 2')
self.assertEqual(len(move_byproduct_advertising.move_line_ids), 2, 'Their should be 2 move lines')
self.assertEqual(move_byproduct_advertising.move_line_ids.mapped('lot_id'), self.advertise_1 | self.advertise_2, 'Wrong serial numbers used')
def test_workorder_4(self):
"""Produce 1 unit in a workorder with lot1, 2 units of this lot1 in the
second workorder. Come back to the WO 1 and try to produce something else
than lot1. It should raise an error """
self.bom_submarine.bom_line_ids.write({'operation_id': False})
# Use 'Secondary assembly routing (3 operations)'
self.bom_submarine.write({
'operation_ids': [
(6, 0, 0),
(0, 0, {'name': 'Long time assembly',
'workcenter_id': self.mrp_workcenter_3.id,
'time_cycle': 180,
'sequence': 15,
}),
(0, 0, {'workcenter_id': self.mrp_workcenter_3.id,
'name': 'Testing',
'time_cycle': 60,
'sequence': 10,
}),
(0, 0, {'workcenter_id': self.mrp_workcenter_3.id,
'name': 'Testing',
'time_cycle': 60,
'sequence': 10,
}),
],
})
self.submarine_pod.tracking = 'lot'
lot1 = self.env['stock.lot'].create({
'product_id': self.submarine_pod.id,
'name': 'lot1',
'company_id': self.env.company.id,
})
lot2 = self.env['stock.lot'].create({
'product_id': self.submarine_pod.id,
'name': 'lot2',
'company_id': self.env.company.id,
})
mrp_order_form = Form(self.env['mrp.production'])
mrp_order_form.product_id = self.submarine_pod
mrp_order_form.product_qty = 2
production = mrp_order_form.save()
production.action_confirm()
production.button_plan()
sorted_workorder_ids = production.workorder_ids.sorted()
self.assertEqual(len(sorted_workorder_ids), 3, "wrong number of workorders")
sorted_workorder_ids[0].button_start()
wo_form = Form(sorted_workorder_ids[0], view='mrp_workorder.mrp_workorder_view_form_tablet')
wo_form.qty_producing = 1
wo_form.finished_lot_id = lot1
wo = wo_form.save()
wo.record_production()
self.assertEqual(production.lot_producing_id, lot1)
sorted_workorder_ids[1].button_start()
wo_form = Form(sorted_workorder_ids[1], view='mrp_workorder.mrp_workorder_view_form_tablet')
self.assertEqual(wo_form.qty_remaining, 1, "it left 1 quantity to produce")
self.assertEqual(wo_form.qty_producing, 1, "it suggest 1 quantity to produce")
self.assertEqual(wo_form.finished_lot_id, lot1, "Final lot should be the one entered in previous wo")
wo_form.finished_lot_id = lot1
wo_form.qty_producing = 2
wo = wo_form.save()
wo.record_production()
sorted_workorder_ids_2 = production.procurement_group_id.mrp_production_ids[1].workorder_ids.sorted()
wo_form = Form(sorted_workorder_ids_2[0], view='mrp_workorder.mrp_workorder_view_form_tablet')
self.assertEqual(wo_form.qty_remaining, 1, "it left 1 quantity to produce")
self.assertEqual(wo_form.qty_producing, 1, "it suggest 1 quantity to produce")
wo_form.finished_lot_id = lot2
wo_form.qty_producing = 1
wo = wo_form.save()
wo.record_production()
backorder = production.procurement_group_id.mrp_production_ids[1]
self.assertEqual(production.lot_producing_id, lot1)
self.assertEqual(backorder.lot_producing_id, lot2)
def test_workorder_5(self):
"""Test production of 2 lots in one workorder then check than the workorder
line are well split in the second"""
self.bom_submarine.bom_line_ids.write({'operation_id': False})
# Use 'Secondary assembly routing (3 operations)'
#self.bom_submarine.routing_id = self.mrp_routing_1
self.bom_submarine.write({
'operation_ids': [
(6, 0, 0),
(0, 0, {'name': 'Long time assembly',
'workcenter_id': self.mrp_workcenter_3.id,
'time_cycle': 180,
'sequence': 15,
}),
(0, 0, {'workcenter_id': self.mrp_workcenter_3.id,
'name': 'Testing',
'time_cycle': 60,
'sequence': 10,
}),
(0, 0, {'workcenter_id': self.mrp_workcenter_3.id,
'name': 'Testing',
'time_cycle': 60,
'sequence': 10,
}),
],
})
self.submarine_pod.tracking = 'lot'
lot1 = self.env['stock.lot'].create({
'product_id': self.submarine_pod.id,
'name': 'lot1',
'company_id': self.env.company.id,
})
lot2 = self.env['stock.lot'].create({
'product_id': self.submarine_pod.id,
'name': 'lot2',
'company_id': self.env.company.id,
})
mrp_order_form = Form(self.env['mrp.production'])
mrp_order_form.product_id = self.submarine_pod
mrp_order_form.product_qty = 2
production = mrp_order_form.save()
production.action_confirm()
production.button_plan()
self.assertEqual(len(production.workorder_ids), 3, "wrong number of workorders")
sorted_workorder_ids = production.workorder_ids.sorted()
sorted_workorder_ids[0].button_start()
wo_form = Form(sorted_workorder_ids[0], view='mrp_workorder.mrp_workorder_view_form_tablet')
wo_form.qty_producing = 1
wo_form.finished_lot_id = lot1
wo = wo_form.save()
action = wo.record_production()
wo_form = Form(self.env['mrp.workorder'].browse(action['res_id']), view='mrp_workorder.mrp_workorder_view_form_tablet')
wo_form.finished_lot_id = lot2
wo = wo_form.save()
wo.record_production()
sorted_workorder_ids[1].button_start()
wo_form = Form(sorted_workorder_ids[1], view='mrp_workorder.mrp_workorder_view_form_tablet')
self.assertEqual(wo_form.qty_remaining, 1, "it left 1 quantity to produce")
self.assertEqual(wo_form.qty_producing, 1, "it suggest 1 quantity to produce")
self.assertEqual(wo_form.finished_lot_id, lot1, "Final lot should be the one entered in previous wo")
wo = wo_form.save()
action = wo.record_production()
wo_form = Form(self.env['mrp.workorder'].browse(action['res_id']), view='mrp_workorder.mrp_workorder_view_form_tablet')
self.assertEqual(wo_form.qty_remaining, 1, "it left 1 quantity to produce")
self.assertEqual(wo_form.qty_producing, 1, "it suggest 1 quantity to produce")
self.assertEqual(wo_form.finished_lot_id, lot2, "Final lot should be the one entered in previous wo")
wo = wo_form.save()
wo.record_production()
sorted_workorder_ids[2].button_start()
wo_form = Form(sorted_workorder_ids[2], view='mrp_workorder.mrp_workorder_view_form_tablet')
self.assertEqual(wo_form.qty_remaining, 1, "it left 1 quantity to produce")
self.assertEqual(wo_form.qty_producing, 1, "it suggest 1 quantity to produce")
self.assertEqual(wo_form.finished_lot_id, lot1, "Final lot should be the one entered in previous wo")
wo = wo_form.save()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.component_id, self.elon_musk, "Should be a register component check")
self.assertEqual(qc_form.qty_done, 1, "Component is serial tracked")
self.assertEqual(qc_form.component_remaining_qty, 1, "Qty_producing is 1")
qc_form.lot_id = self.elon1
qc = qc_form.save()
qc._next()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.component_id, self.metal_cylinder, "Should be a register component check")
self.assertEqual(qc_form.qty_done, 2, "2 components to produce")
self.assertEqual(qc_form.component_remaining_qty, 2, "Qty_producing is 1")
qc_form.lot_id = self.mc1
qc = qc_form.save()
qc._next()
action = wo.record_production()
wo_form = Form(self.env['mrp.workorder'].browse(action['res_id']), view='mrp_workorder.mrp_workorder_view_form_tablet')
self.assertEqual(wo_form.finished_lot_id, lot2, "Final lot should be the one entered in previous wo")
self.assertEqual(wo_form.qty_remaining, 1, "it left 1 quantity to produce")
self.assertEqual(wo_form.qty_producing, 1, "it suggest 1 quantity to produce")
wo = wo_form.save()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.component_id, self.elon_musk, "Should be a register component check")
self.assertEqual(qc_form.qty_done, 1, "Component is serial tracked")
self.assertEqual(qc_form.component_remaining_qty, 1, "Qty_producing is 1")
qc_form.lot_id = self.elon2
qc = qc_form.save()
qc._next()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.component_id, self.metal_cylinder, "Should be a register component check")
self.assertEqual(qc_form.qty_done, 2, "Component is serial tracked")
self.assertEqual(qc_form.component_remaining_qty, 2, "Qty_producing is 1")
qc_form.lot_id = self.mc1
qc = qc_form.save()
qc._next()
wo.record_production()
def test_workorder_duplicate_sn(self):
"""produce a finished product tracked by serial number 2 times with the
same SN. Check that an error is raised the second time"""
self.bom_submarine.bom_line_ids.write({'operation_id': False})
# Use 'Secondary assembly routing (3 operations)'
self.bom_submarine.operation_ids = False
self.bom_submarine.write({
'operation_ids': [(0, 0, {
'workcenter_id': self.mrp_workcenter_3.id,
'name': 'Manual Assembly',
'time_cycle': 60,
})]
})
#self.bom_submarine.routing_id = self.mrp_routing_0
self.submarine_pod.tracking = 'serial'
sn1 = self.env['stock.lot'].create({
'product_id': self.submarine_pod.id,
'name': 'sn1',
'company_id': self.env.company.id,
})
mrp_order_form = Form(self.env['mrp.production'])
mrp_order_form.product_id = self.submarine_pod
mrp_order_form.product_qty = 1
production = mrp_order_form.save()
production.action_confirm()
production.button_plan()
production.workorder_ids[0].button_start()
wo_form = Form(production.workorder_ids[0], view='mrp_workorder.mrp_workorder_view_form_tablet')
wo_form.finished_lot_id = sn1
wo = wo_form.save()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
qc_form.lot_id = self.elon1
qc = qc_form.save()
qc._next()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
qc_form.lot_id = self.mc1
qc = qc_form.save()
qc._next()
wo.do_finish()
production.button_mark_done()
mrp_order_form = Form(self.env['mrp.production'])
mrp_order_form.product_id = self.submarine_pod
production = mrp_order_form.save()
production.action_confirm()
production.button_plan()
production.workorder_ids[0].button_start()
wo_form = Form(production.workorder_ids[0], view='mrp_workorder.mrp_workorder_view_form_tablet')
wo_form.finished_lot_id = sn1
wo = wo_form.save()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
qc_form.lot_id = self.elon1
qc = qc_form.save()
with self.assertRaises(UserError):
qc._next()
wo.record_production()
def test_post_inventory(self):
"""Test production of 2 finished products in one by one and posting intermediate inventory
between the two production"""
mrp_order_form = Form(self.env['mrp.production'])
mrp_order_form.product_id = self.submarine_pod
mrp_order_form.product_qty = 2
production = mrp_order_form.save()
production.action_confirm()
production.action_assign()
production.button_plan()
self.assertEqual(len(production.move_raw_ids), 3, "wrong number of raw moves")
sorted_workorder_ids = production.workorder_ids.sorted()
sorted_workorder_ids[0].button_start()
wo_form = Form(sorted_workorder_ids[0], view='mrp_workorder.mrp_workorder_view_form_tablet')
wo_form.finished_lot_id = self.sp1
wo = wo_form.save()
wo.current_quality_check_id._next()
wo.record_production()
sorted_workorder_ids[1].button_start()
wo_form = Form(sorted_workorder_ids[1], view='mrp_workorder.mrp_workorder_view_form_tablet')
wo = wo_form.save()
wo.current_quality_check_id._next()
wo.record_production()
sorted_workorder_ids[2].button_start()
wo_form = Form(sorted_workorder_ids[2], view='mrp_workorder.mrp_workorder_view_form_tablet')
wo = wo_form.save()
wo.record_production()
production._post_inventory()
self.assertEqual(len(production.move_raw_ids), 3, "wrong number of raw moves")
done_raw_moves = production.move_raw_ids.filtered(lambda move: move.state == 'done')
self.assertEqual(len(done_raw_moves), 3, "wrong number of done raw moves")
self.assertEqual(done_raw_moves[0].quantity_done, 1, "Components are not consumed")
self.assertEqual(done_raw_moves[1].quantity_done, 12, "Components are not consumed")
self.assertEqual(done_raw_moves[2].quantity_done, 2, "Components are not consumed")
self.assertEqual(len(production.procurement_group_id.mrp_production_ids), 2)
backorder = production.procurement_group_id.mrp_production_ids[-1]
backorder.action_assign()
assigned_raw_moves = backorder.move_raw_ids.filtered(lambda move: move.state == 'assigned')
self.assertEqual(len(assigned_raw_moves), 3, "wrong number of reserved raw moves")
done_finished_move = production.move_finished_ids.filtered(lambda move: move.state == 'done')
self.assertEqual(len(done_finished_move), 1, "wrong number of done finished moves")
self.assertEqual(done_finished_move.quantity_done, 1, "finished product are not produced")
sorted_workorder_ids = backorder.workorder_ids.sorted()
wo_form = Form(sorted_workorder_ids[0], view='mrp_workorder.mrp_workorder_view_form_tablet')
wo_form.finished_lot_id = self.sp2
wo = wo_form.save()
wo.current_quality_check_id._next()
wo.record_production()
wo_form = Form(sorted_workorder_ids[1], view='mrp_workorder.mrp_workorder_view_form_tablet')
wo = wo_form.save()
wo.current_quality_check_id._next()
wo.record_production()
wo_form = Form(sorted_workorder_ids[2], view='mrp_workorder.mrp_workorder_view_form_tablet')
wo = wo_form.save()
wo.record_production()
backorder.button_mark_done()
done_raw_moves = (production | backorder).move_raw_ids.filtered(lambda move: move.state == 'done')
self.assertEqual(len(done_raw_moves), 6, "wrong number of done raw moves")
drm_elon = done_raw_moves.filtered(lambda move: move.product_id == self.elon_musk)
drm_metal = done_raw_moves.filtered(lambda move: move.product_id == self.metal_cylinder)
drm_child = done_raw_moves.filtered(lambda move: move.product_id == self.trapped_child)
self.assertEqual(drm_elon[0].quantity_done, 1, "Components are not consumed")
self.assertEqual(drm_elon[1].quantity_done, 1, "Components are not consumed")
self.assertEqual(drm_metal[0].quantity_done, 2, "Components are not consumed")
self.assertEqual(drm_metal[1].quantity_done, 2, "Components are not consumed")
self.assertEqual(drm_child[0].quantity_done, 12, "Components are not consumed")
self.assertEqual(drm_child[1].quantity_done, 12, "Components are not consumed")
done_finished_move = (production | backorder).move_finished_ids.filtered(lambda move: move.state == 'done')
self.assertEqual(len(done_finished_move), 2, "wrong number of done finished moves")
self.assertEqual(done_finished_move[0].quantity_done, 1, "finished product are not produced")
self.assertEqual(done_finished_move[1].quantity_done, 1, "finished product are not produced")
def test_add_component_2(self):
""" Adds an extra component when qty_producing is 0 (default value when opening tablet view for a product without tracking).
Checks that the quantity consumed of the additional component is correct and not doubled as before """
mrp_order_form = Form(self.env['mrp.production'])
table = self.env['product.product'].create({
'name': 'Table',
'type': 'product',
'tracking': 'none'})
table_leg = self.env['product.product'].create({
'name': 'Table Leg',
'type': 'product',
'tracking': 'none'})
bom_table = self.env['mrp.bom'].create({
'product_tmpl_id': table.product_tmpl_id.id,
'product_qty': 1.0,
'operation_ids': [
(0, 0, {'name': 'Cutting Machine', 'workcenter_id': self.workcenter_1.id, 'time_cycle': 12, 'sequence': 1}),
]})
self.env['mrp.bom.line'].create({
'product_id': table_leg.id,
'product_qty': 2.0,
'bom_id': bom_table.id,
'operation_id': bom_table.operation_ids[0].id})
mrp_order_form.product_id = table
mrp_order_form.product_qty = 10
production = mrp_order_form.save()
production.action_confirm()
production.workorder_ids[0].button_start()
# Open tablet view
wo_form = Form(production.workorder_ids[0], view='mrp_workorder.mrp_workorder_view_form_tablet')
wo = wo_form.save()
# Add an additional product
additional_form = Form(self.env['mrp_workorder.additional.product'].with_context({
'default_workorder_id': wo.id,
'default_type': 'component',
}))
additional_form.product_id = self.product_1
additional_form.product_qty = 6
additional_wizard = additional_form.save()
additional_wizard.add_product()
wo_form = Form(production.workorder_ids[0], view='mrp_workorder.mrp_workorder_view_form_tablet')
wo_form.qty_producing = 5
wo = wo_form.save()
wo.current_quality_check_id._next()
self.assertEqual(production.move_raw_ids[1].quantity_done, 3)
# Same test for byproducts
mrp_order_form = Form(self.env['mrp.production'])
mrp_order_form.product_id = table
mrp_order_form.product_qty = 10
production = mrp_order_form.save()
production.action_confirm()
production.workorder_ids[0].button_start()
wo_form = Form(production.workorder_ids[0], view='mrp_workorder.mrp_workorder_view_form_tablet')
wo = wo_form.save()
additional_form = Form(self.env['mrp_workorder.additional.product'].with_context({
'default_workorder_id': wo.id,
'default_type': 'byproduct',
}))
additional_form.product_id = self.product_1
additional_form.product_qty = 6
additional_wizard = additional_form.save()
additional_wizard.add_product()
wo_form = Form(production.workorder_ids[0], view='mrp_workorder.mrp_workorder_view_form_tablet')
wo_form.qty_producing = 5
wo = wo_form.save()
wo.current_quality_check_id._next()
self.assertEqual(production.move_byproduct_ids[0].quantity_done, 3)
def test_produce_more_than_planned(self):
self.env['quality.point'].create({
'product_ids': [(4, self.submarine_pod.id)],
'picking_type_ids': [(4, self.env['stock.picking.type'].search([('code', '=', 'mrp_operation')], limit=1).id)],
'operation_id': self.bom_submarine.operation_ids[0].id,
'test_type_id': self.env.ref('mrp_workorder.test_type_register_consumed_materials').id,
'component_id': self.trapped_child.id,
})
self.bom_submarine.bom_line_ids.filtered(lambda line: line.product_id == self.trapped_child).operation_id = self.bom_submarine.operation_ids[0]
self.submarine_pod.tracking = 'lot'
mo_form = Form(self.env['mrp.production'])
mo_form.product_id = self.submarine_pod
mo_form.bom_id = self.bom_submarine
mo_form.product_qty = 1
mo = mo_form.save()
mo.action_confirm()
mo.button_plan()
sorted_workorder_ids = mo.workorder_ids.sorted()
wo = sorted_workorder_ids[0]
wo.button_start()
wo_form = Form(wo, view='mrp_workorder.mrp_workorder_view_form_tablet')
wo_form.qty_producing = 5
wo_form.finished_lot_id = self.sp1
wo = wo_form.save()
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.qty_done, 60, 'The suggested component qty_done is wrong')
self.assertEqual(qc_form.component_remaining_qty, 60, 'The component remaining quantity is wrong')
qc = qc_form.save()
wo.current_quality_check_id._next()
wo_form = Form(wo, view='mrp_workorder.mrp_workorder_view_form_tablet')
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
qc_form.lot_id = self.mc1
# since lot tracked products are reserved, don't auto multiply amount
self.assertEqual(qc_form.qty_done, 2, 'The suggested component qty_done is wrong')
self.assertEqual(qc_form.component_remaining_qty, 10, 'The component remaining quantity is wrong')
qc = qc_form.save()
qc._next()
wo.do_finish()
self.assertEqual(mo.qty_producing, 5)
def test_suggested_lot_in_multi_step(self):
"""Suggest the assigned lot in multi step system."""
self.warehouse = self.env.ref('stock.warehouse0')
self.env['quality.point'].create({
'product_ids': [(4, self.submarine_pod.id)],
'picking_type_ids': [(4, self.env['stock.picking.type'].search([('code', '=', 'mrp_operation')], limit=1).id)],
'operation_id': self.bom_submarine.operation_ids[0].id,
'test_type_id': self.env.ref('mrp_workorder.test_type_register_consumed_materials').id,
'component_id': self.elon_musk.id,
})
self.warehouse.manufacture_steps = 'pbm'
self.submarine_pod.tracking = 'none'
self.bom_submarine.bom_line_ids.filtered(lambda l: l.product_id.id != self.elon_musk.id).unlink()
self.bom_submarine.operation_ids[1:].unlink()
mrp_order_form = Form(self.env['mrp.production'])
mrp_order_form.product_id = self.submarine_pod
mrp_order_form.product_qty = 1
production = mrp_order_form.save()
production.action_confirm()
production.button_plan()
production.picking_ids.action_assign()
production.picking_ids.move_line_ids.lot_id = self.elon2
production.picking_ids.move_line_ids.qty_done = 1
production.picking_ids.button_validate()
wo = production.workorder_ids
wo.button_start()
self.assertEqual(production.move_raw_ids.move_line_ids.lot_id, self.elon2, "Lot should be assigned.")
self.assertEqual(wo.lot_id, self.elon2, "Lot should be set in the step")
def test_step_by_product_variant(self):
who_attr = self.env['product.attribute'].create({'name': 'Who ?'})
a1 = self.env['product.attribute.value'].create({'name': 'V0hFCg==', 'attribute_id': who_attr.id})
a2 = self.env['product.attribute.value'].create({'name': 'QVJN', 'attribute_id': who_attr.id})
a3 = self.env['product.attribute.value'].create({'name': 'UllW', 'attribute_id': who_attr.id})
product_who = self.env['product.template'].create({
'name': 'Odoo staff',
'attribute_line_ids': [(0, 0, {
'attribute_id': who_attr.id,
'value_ids': [(6, 0, [a1.id, a2.id, a3.id])],
})]
})
product_a1 = product_who.product_variant_ids.filtered(lambda v: a1 in v.product_template_attribute_value_ids.product_attribute_value_id)
product_a2 = product_who.product_variant_ids.filtered(lambda v: a2 in v.product_template_attribute_value_ids.product_attribute_value_id)
product_a3 = product_who.product_variant_ids.filtered(lambda v: a3 in v.product_template_attribute_value_ids.product_attribute_value_id)
bom_who = self.env['mrp.bom'].create({
'code': 'To be ready',
'product_tmpl_id': product_who.id,
'product_qty': 1.0,
'bom_line_ids': [
(0, 0, {'product_id': self.trapped_child.id, 'product_qty': 1}),
],
'operation_ids': [
(0, 0, {'name': 'Be ready', 'workcenter_id': self.workcenter_1.id, 'time_cycle': 60, 'sequence': 1}),
]
})
p1 = self.env['quality.point'].create({
'product_ids': [(4, product_a1.id)],
'picking_type_ids': [(4, self.env['stock.picking.type'].search([('code', '=', 'mrp_operation')], limit=1).id)],
'operation_id': bom_who.operation_ids[0].id,
'test_type_id': self.env.ref('quality.test_type_instructions').id,
'note': 'Installing VIM (pcs xi ipzth adi du ixbt)',
})
p2 = self.env['quality.point'].create({
'product_ids': [(4, product_a2.id)],
'picking_type_ids': [(4, self.env['stock.picking.type'].search([('code', '=', 'mrp_operation')], limit=1).id)],
'operation_id': bom_who.operation_ids[0].id,
'test_type_id': self.env.ref('quality.test_type_instructions').id,
'note': 'Taking lot of coffee with UElN',
})
mrp_order_form = Form(self.env['mrp.production'])
mrp_order_form.product_id = product_a1
production_a1 = mrp_order_form.save()
mrp_order_form = Form(self.env['mrp.production'])
mrp_order_form.product_id = product_a2
production_a2 = mrp_order_form.save()
mrp_order_form = Form(self.env['mrp.production'])
mrp_order_form.product_id = product_a3
production_a3 = mrp_order_form.save()
self.assertEqual(production_a1.bom_id, bom_who)
self.assertEqual(production_a2.bom_id, bom_who)
self.assertEqual(production_a3.bom_id, bom_who)
production_a1.action_confirm()
(production_a2 | production_a3).action_confirm()
self.assertEqual(len(production_a1.workorder_ids.check_ids), 1)
self.assertEqual(production_a1.workorder_ids.check_ids.point_id, p1)
self.assertEqual(len(production_a2.workorder_ids.check_ids), 1)
self.assertEqual(production_a2.workorder_ids.check_ids.point_id, p2)
self.assertEqual(len(production_a3.workorder_ids.check_ids), 0)
def test_add_workorder_into_a_backorder(self):
""" Checks a new workorder can be created and processed into a backorder."""
(self.submarine_pod | self.elon_musk | self.metal_cylinder).tracking = 'none'
self.bom_submarine.consumption = 'flexible'
def process_workorder(workorders, qty, next_and_finish=False):
for wo in workorders:
wo.button_start()
wo_form = Form(wo, view='mrp_workorder.mrp_workorder_view_form_tablet')
wo_form.qty_producing = qty
wo = wo_form.save()
if next_and_finish:
if wo.current_quality_check_id:
wo.current_quality_check_id._next()
wo.do_finish()
elif wo.current_quality_check_id:
wo.current_quality_check_id.action_continue()
# Creates a MO with 2 WO.
mo_form = Form(self.env['mrp.production'])
mo_form.product_id = self.submarine_pod
mo_form.product_qty = 10
mo = mo_form.save()
mo.action_confirm()
mo.button_plan()
# Processes partially the workorders.
process_workorder(mo.workorder_ids.sorted(), 2)
# Marks the MO as done and creates a backorder.
action = mo.button_mark_done()
backorder_form = Form(self.env[action['res_model']].with_context(**action['context']))
backorder_form.save().action_backorder()
backorder = mo.procurement_group_id.mrp_production_ids[-1]
self.assertEqual(mo.state, 'done')
self.assertEqual(backorder.state, 'confirmed')
self.assertEqual(len(backorder.workorder_ids), 3)
self.assertEqual(backorder.workorder_ids.mapped('qty_production'), [8.0, 8.0, 8.0])
# Adds a new WO in the backorder.
mo_form = Form(backorder)
with mo_form.workorder_ids.new() as wo_line:
wo_line.name = "OP-SP"
wo_line.workcenter_id = self.workcenter_1
mo_form.save()
# Again, processes partially the workorders.
process_workorder(backorder.workorder_ids.sorted(), 5, True)
def test_operations_with_test_type_register_consumed_materials(self):
""" Production with a strict consumption
Check that operation must contain related consumption material"""
# create operation
operation1 = self.env['mrp.routing.workcenter'].create({
'name': 'Operation1',
'bom_id': self.bom_2.id,
'workcenter_id': self.workcenter_2.id,
})
operation2 = self.env['mrp.routing.workcenter'].create({
'name': 'Operation2',
'bom_id': self.bom_2.id,
'workcenter_id': self.workcenter_2.id,
})
# update operations in bom
self.bom_2.write({'operation_ids': [(6, 0, [operation1.id, operation2.id])]})
# create quality point
self.env['quality.point'].create({
'product_ids': [(6, 0, self.product_5.ids)],
'picking_type_ids': [(6, 0, self.bom_2.picking_type_id.ids)],
'operation_id': operation1.id,
'test_type_id': self.env.ref('mrp_workorder.test_type_register_consumed_materials').id,
'component_id': self.product_3.id,
})
# update quantities
self.env['stock.quant']._update_available_quantity(self.product_3, self.location_1, 20.0)
self.env['stock.quant']._update_available_quantity(self.product_4, self.location_1, 20.0)
# create a mo
mo_form = Form(self.env['mrp.production'])
mo_form.product_id = self.product_5
mo_form.bom_id = self.bom_2
mo_form.product_qty = 2
mo = mo_form.save()
mo.action_confirm()
mo.action_assign()
mo.button_plan()
wo = mo.workorder_ids[0]
wo.button_start()
wo_form = Form(wo, view='mrp_workorder.mrp_workorder_view_form_tablet')
wo_form.qty_producing = 3
wo = wo_form.save()
self.assertEqual(len(wo.check_ids), 1, "their should be 1 quality check")
qc_form = Form(wo.current_quality_check_id, view='mrp_workorder.quality_check_view_form_tablet')
self.assertEqual(qc_form.component_id, self.product_3, 'operation must contain related consumption material')