1537 lines
78 KiB
Python
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')
|