# Part of Odoo. See LICENSE file for full copyright and licensing details. # -*- coding: utf-8 -*- from odoo.addons.mrp.tests.common import TestMrpCommon from odoo.tests import tagged, Form, HttpCase @tagged('post_install', '-at_install') class TestTourManualConsumption(HttpCase): def test_mrp_manual_consumption(self): """Test manual consumption mechanism. Test when manual consumption is True, quantity won't be updated automatically. Bom line with tracked products or operations should be set to manual consumption automatically. Also test that when manually change quantity, manual consumption will be set to True. Also test when create backorder, the manual consumption should be set according to the bom. """ Product = self.env['product.product'] product_finish = Product.create({ 'name': 'finish', 'type': 'product', 'tracking': 'none',}) product_nt = Product.create({ 'name': 'No tracking', 'type': 'product', 'tracking': 'none',}) product_sn = Product.create({ 'name': 'Serial', 'type': 'product', 'tracking': 'serial',}) product_lot = Product.create({ 'name': 'Lot', 'type': 'product', 'tracking': 'lot',}) bom = self.env['mrp.bom'].create({ 'product_id': product_finish.id, 'product_tmpl_id': product_finish.product_tmpl_id.id, 'product_qty': 1, 'type': 'normal', 'bom_line_ids': [ (0, 0, {'product_id': product_nt.id, 'product_qty': 1}), (0, 0, {'product_id': product_sn.id, 'product_qty': 1}), (0, 0, {'product_id': product_lot.id, 'product_qty': 1}), ], }) mo_form = Form(self.env['mrp.production']) mo_form.product_id = product_finish mo_form.bom_id = bom mo_form.product_qty = 10 mo = mo_form.save() mo.action_confirm() mo.action_assign() # test no updating mo_form = Form(mo) mo_form.qty_producing = 5 mo = mo_form.save() move_nt, move_sn, move_lot = mo.move_raw_ids self.assertEqual(move_nt.manual_consumption, False) self.assertEqual(move_nt.quantity, 5) self.assertTrue(move_nt.picked) self.assertEqual(move_sn.manual_consumption, True) self.assertEqual(move_sn.quantity, 5) self.assertFalse(move_sn.picked) self.assertEqual(move_lot.manual_consumption, True) self.assertEqual(move_lot.quantity, 5) self.assertFalse(move_lot.picked) action_id = self.env.ref('mrp.menu_mrp_production_action').action url = "/web#model=mrp.production&view_type=form&action=%s&id=%s" % (str(action_id.id), str(mo.id)) self.start_tour(url, "test_mrp_manual_consumption", login="admin", timeout=100) self.assertEqual(move_nt.manual_consumption, True) self.assertEqual(move_nt.quantity, 6.0) self.assertEqual(move_sn.manual_consumption, True) self.assertEqual(move_sn.quantity, 0) self.assertEqual(move_lot.manual_consumption, True) self.assertEqual(move_lot.quantity, 0) backorder = mo.procurement_group_id.mrp_production_ids - mo move_nt = backorder.move_raw_ids.filtered(lambda m: m.product_id == product_nt) move_sn = backorder.move_raw_ids.filtered(lambda m: m.product_id == product_sn) move_lot = backorder.move_raw_ids.filtered(lambda m: m.product_id == product_lot) self.assertEqual(move_nt.manual_consumption, False) self.assertEqual(move_sn.manual_consumption, True) self.assertEqual(move_lot.manual_consumption, True) def test_mrp_manual_consumption_02(self): """ test that when a new quantity is manually set for a component, and the field picked is set to True, and the MO is marked as done, the component quantity is not overwritten. """ Product = self.env['product.product'] product_finish = Product.create({ 'name': 'finish', 'type': 'product', 'tracking': 'none',}) product_nt = Product.create({ 'name': 'No tracking', 'type': 'product', 'tracking': 'none',}) bom = self.env['mrp.bom'].create({ 'product_id': product_finish.id, 'product_tmpl_id': product_finish.product_tmpl_id.id, 'product_qty': 1, 'type': 'normal', 'bom_line_ids': [ (0, 0, {'product_id': product_nt.id, 'product_qty': 1, 'manual_consumption': True}), ], }) mo_form = Form(self.env['mrp.production']) mo_form.product_id = product_finish mo_form.bom_id = bom mo_form.product_qty = 10 mo = mo_form.save() mo.action_confirm() self.assertEqual(mo.state, 'confirmed') move_nt = mo.move_raw_ids self.assertEqual(move_nt.manual_consumption, True) self.assertEqual(move_nt.quantity, 0) self.assertFalse(move_nt.picked) action_id = self.env.ref('mrp.menu_mrp_production_action').action url = "/web#model=mrp.production&view_type=form&action=%s&id=%s" % (str(action_id.id), str(mo.id)) self.start_tour(url, "test_mrp_manual_consumption_02", login="admin", timeout=100) self.assertEqual(move_nt.manual_consumption, True) self.assertEqual(move_nt.picked, True) self.assertEqual(move_nt.quantity, 16.0) class TestManualConsumption(TestMrpCommon): @classmethod def setUpClass(cls): super().setUpClass() cls.stock_location = cls.env.ref('stock.stock_location_stock') cls.env.ref('base.group_user').write({'implied_ids': [(4, cls.env.ref('stock.group_production_lot').id)]}) def test_manual_consumption_backorder_00(self): """Test when use_auto_consume_components_lots is not set, manual consumption of the backorder is correctly set. """ mo, _, _final, c1, c2 = self.generate_mo('none', 'lot', 'none', qty_final=2) self.assertTrue(mo.move_raw_ids.filtered(lambda m: m.product_id == c1).manual_consumption) self.assertFalse(mo.move_raw_ids.filtered(lambda m: m.product_id == c2).manual_consumption) lot = self.env['stock.lot'].create({ 'name': 'lot', 'product_id': c1.id, 'company_id': self.env.company.id, }) self.env['stock.quant']._update_available_quantity(c1, self.stock_location, 8, lot_id=lot) self.env['stock.quant']._update_available_quantity(c2, self.stock_location, 2) mo.action_assign() mo_form = Form(mo) mo_form.qty_producing = 1 mo_form.save() self.assertEqual(sum(mo.move_raw_ids.filtered(lambda m: m.product_id.id == c1.id).mapped("quantity")), 4) self.assertEqual(sum(mo.move_raw_ids.filtered(lambda m: m.product_id.id == c2.id).mapped("quantity")), 1) self.assertEqual(sorted(mo.move_raw_ids.mapped('picked')), sorted([False, True])) details_operation_form = Form(mo.move_raw_ids.filtered(lambda m: m.product_id == c1), view=self.env.ref('stock.view_stock_move_operations')) with details_operation_form.move_line_ids.edit(0) as ml: ml.quantity = 4 ml.lot_id = lot details_operation_form.save() action = mo.button_mark_done() backorder = Form(self.env['mrp.production.backorder'].with_context(**action['context'])) backorder.save().action_backorder() backorder_mo = mo.procurement_group_id.mrp_production_ids[-1] self.assertTrue(backorder_mo.move_raw_ids.filtered(lambda m: m.product_id == c1).manual_consumption) self.assertFalse(backorder_mo.move_raw_ids.filtered(lambda m: m.product_id == c2).manual_consumption) def test_manual_consumption_backorder_01(self): """Test when use_auto_consume_components_lots is set, manual consumption of the backorder is correctly set. """ picking_type = self.env['stock.picking.type'].search([('code', '=', 'mrp_operation')])[0] picking_type.use_auto_consume_components_lots = True mo, _, _final, c1, c2 = self.generate_mo('none', 'lot', 'none', qty_final=2) self.assertFalse(mo.move_raw_ids.filtered(lambda m: m.product_id == c1).manual_consumption) self.assertFalse(mo.move_raw_ids.filtered(lambda m: m.product_id == c2).manual_consumption) lot = self.env['stock.lot'].create({ 'name': 'lot', 'product_id': c1.id, 'company_id': self.env.company.id, }) self.env['stock.quant']._update_available_quantity(c1, self.stock_location, 8, lot_id=lot) self.env['stock.quant']._update_available_quantity(c2, self.stock_location, 2) mo.action_assign() mo_form = Form(mo) mo_form.qty_producing = 1 mo_form.save() self.assertEqual(sum(mo.move_raw_ids.filtered(lambda m: m.product_id.id == c1.id).mapped("quantity")), 4) self.assertEqual(sum(mo.move_raw_ids.filtered(lambda m: m.product_id.id == c2.id).mapped("quantity")), 1) action = mo.button_mark_done() backorder = Form(self.env['mrp.production.backorder'].with_context(**action['context'])) backorder.save().action_backorder() backorder_mo = mo.procurement_group_id.mrp_production_ids[-1] self.assertFalse(backorder_mo.move_raw_ids.filtered(lambda m: m.product_id == c1).manual_consumption) self.assertFalse(backorder_mo.move_raw_ids.filtered(lambda m: m.product_id == c2).manual_consumption) def test_manual_consumption_split_merge_00(self): """Test manual consumption is correctly set after split or merge. """ # Change 'Units' rounding to 1 (integer only quantities) self.uom_unit.rounding = 1 # Create a mo for 10 products mo, _, _, p1, p2 = self.generate_mo('none', 'lot', 'none', qty_final=10) self.assertTrue(mo.move_raw_ids.filtered(lambda m: m.product_id == p1).manual_consumption) self.assertFalse(mo.move_raw_ids.filtered(lambda m: m.product_id == p2).manual_consumption) # Split in 3 parts action = mo.action_split() wizard = Form(self.env[action['res_model']].with_context(action['context'])) wizard.counter = 3 action = wizard.save().action_split() for production in mo.procurement_group_id.mrp_production_ids: self.assertTrue(production.move_raw_ids.filtered(lambda m: m.product_id == p1).manual_consumption) self.assertFalse(production.move_raw_ids.filtered(lambda m: m.product_id == p2).manual_consumption) # Merge them back action = mo.procurement_group_id.mrp_production_ids.action_merge() mo = self.env[action['res_model']].browse(action['res_id']) self.assertTrue(mo.move_raw_ids.filtered(lambda m: m.product_id == p1).manual_consumption) self.assertFalse(mo.move_raw_ids.filtered(lambda m: m.product_id == p2).manual_consumption)