diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/mrp/tests/test_backorder.py | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/mrp/tests/test_backorder.py')
| -rw-r--r-- | addons/mrp/tests/test_backorder.py | 360 |
1 files changed, 360 insertions, 0 deletions
diff --git a/addons/mrp/tests/test_backorder.py b/addons/mrp/tests/test_backorder.py new file mode 100644 index 00000000..eadd7847 --- /dev/null +++ b/addons/mrp/tests/test_backorder.py @@ -0,0 +1,360 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo.addons.mrp.tests.common import TestMrpCommon +from odoo.tests import Form +from odoo.tests.common import SavepointCase + + +class TestMrpProductionBackorder(TestMrpCommon): + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.stock_location = cls.env.ref('stock.stock_location_stock') + + def setUp(self): + super().setUp() + warehouse_form = Form(self.env['stock.warehouse']) + warehouse_form.name = 'Test Warehouse' + warehouse_form.code = 'TWH' + self.warehouse = warehouse_form.save() + + def test_no_tracking_1(self): + """Create a MO for 4 product. Produce 4. The backorder button should + not appear and hitting mark as done should not open the backorder wizard. + The name of the MO should be MO/001. + """ + mo = self.generate_mo(qty_final=4)[0] + + mo_form = Form(mo) + mo_form.qty_producing = 4 + mo = mo_form.save() + + # No backorder is proposed + self.assertTrue(mo.button_mark_done()) + self.assertEqual(mo._get_quantity_to_backorder(), 0) + self.assertTrue("-001" not in mo.name) + + def test_no_tracking_2(self): + """Create a MO for 4 product. Produce 1. The backorder button should + appear and hitting mark as done should open the backorder wizard. In the backorder + wizard, choose to do the backorder. A new MO for 3 self.untracked_bom should be + created. + The sequence of the first MO should be MO/001-01, the sequence of the second MO + should be MO/001-02. + Check that all MO are reachable through the procurement group. + """ + production, _, _, product_to_use_1, _ = self.generate_mo(qty_final=4, qty_base_1=3) + self.assertEqual(production.state, 'confirmed') + self.assertEqual(production.reserve_visible, True) + + # Make some stock and reserve + for product in production.move_raw_ids.product_id: + self.env['stock.quant'].with_context(inventory_mode=True).create({ + 'product_id': product.id, + 'inventory_quantity': 100, + 'location_id': production.location_src_id.id, + }) + production.action_assign() + self.assertEqual(production.state, 'confirmed') + self.assertEqual(production.reserve_visible, False) + + mo_form = Form(production) + mo_form.qty_producing = 1 + production = mo_form.save() + + action = production.button_mark_done() + backorder = Form(self.env['mrp.production.backorder'].with_context(**action['context'])) + backorder.save().action_backorder() + + # Two related MO to the procurement group + self.assertEqual(len(production.procurement_group_id.mrp_production_ids), 2) + + # Check MO backorder + mo_backorder = production.procurement_group_id.mrp_production_ids[-1] + self.assertEqual(mo_backorder.product_id.id, production.product_id.id) + self.assertEqual(mo_backorder.product_qty, 3) + self.assertEqual(sum(mo_backorder.move_raw_ids.filtered(lambda m: m.product_id.id == product_to_use_1.id).mapped("product_uom_qty")), 9) + self.assertEqual(mo_backorder.reserve_visible, False) # the reservation of the first MO should've been moved here + + def test_no_tracking_pbm_1(self): + """Create a MO for 4 product. Produce 1. The backorder button should + appear and hitting mark as done should open the backorder wizard. In the backorder + wizard, choose to do the backorder. A new MO for 3 self.untracked_bom should be + created. + The sequence of the first MO should be MO/001-01, the sequence of the second MO + should be MO/001-02. + Check that all MO are reachable through the procurement group. + """ + with Form(self.warehouse) as warehouse: + warehouse.manufacture_steps = 'pbm' + + production, _, product_to_build, product_to_use_1, product_to_use_2 = self.generate_mo(qty_base_1=4, qty_final=4, picking_type_id=self.warehouse.manu_type_id) + + move_raw_ids = production.move_raw_ids + self.assertEqual(len(move_raw_ids), 2) + self.assertEqual(set(move_raw_ids.mapped("product_id")), {product_to_use_1, product_to_use_2}) + + pbm_move = move_raw_ids.move_orig_ids + self.assertEqual(len(pbm_move), 2) + self.assertEqual(set(pbm_move.mapped("product_id")), {product_to_use_1, product_to_use_2}) + self.assertFalse(pbm_move.move_orig_ids) + + mo_form = Form(production) + mo_form.qty_producing = 1 + production = mo_form.save() + self.assertEqual(sum(pbm_move.filtered(lambda m: m.product_id.id == product_to_use_1.id).mapped("product_qty")), 16) + self.assertEqual(sum(pbm_move.filtered(lambda m: m.product_id.id == product_to_use_2.id).mapped("product_qty")), 4) + + action = production.button_mark_done() + backorder = Form(self.env['mrp.production.backorder'].with_context(**action['context'])) + backorder.save().action_backorder() + + mo_backorder = production.procurement_group_id.mrp_production_ids[-1] + self.assertEqual(mo_backorder.delivery_count, 1) + + pbm_move |= mo_backorder.move_raw_ids.move_orig_ids + # Check that quantity is correct + self.assertEqual(sum(pbm_move.filtered(lambda m: m.product_id.id == product_to_use_1.id).mapped("product_qty")), 16) + self.assertEqual(sum(pbm_move.filtered(lambda m: m.product_id.id == product_to_use_2.id).mapped("product_qty")), 4) + + self.assertFalse(pbm_move.move_orig_ids) + + def test_no_tracking_pbm_sam_1(self): + """Create a MO for 4 product. Produce 1. The backorder button should + appear and hitting mark as done should open the backorder wizard. In the backorder + wizard, choose to do the backorder. A new MO for 3 self.untracked_bom should be + created. + The sequence of the first MO should be MO/001-01, the sequence of the second MO + should be MO/001-02. + Check that all MO are reachable through the procurement group. + """ + with Form(self.warehouse) as warehouse: + warehouse.manufacture_steps = 'pbm_sam' + production, _, product_to_build, product_to_use_1, product_to_use_2 = self.generate_mo(qty_base_1=4, qty_final=4, picking_type_id=self.warehouse.manu_type_id) + + move_raw_ids = production.move_raw_ids + self.assertEqual(len(move_raw_ids), 2) + self.assertEqual(set(move_raw_ids.mapped("product_id")), {product_to_use_1, product_to_use_2}) + + pbm_move = move_raw_ids.move_orig_ids + self.assertEqual(len(pbm_move), 2) + self.assertEqual(set(pbm_move.mapped("product_id")), {product_to_use_1, product_to_use_2}) + self.assertFalse(pbm_move.move_orig_ids) + self.assertEqual(sum(pbm_move.filtered(lambda m: m.product_id.id == product_to_use_1.id).mapped("product_qty")), 16) + self.assertEqual(sum(pbm_move.filtered(lambda m: m.product_id.id == product_to_use_2.id).mapped("product_qty")), 4) + + sam_move = production.move_finished_ids.move_dest_ids + self.assertEqual(len(sam_move), 1) + self.assertEqual(sam_move.product_id.id, product_to_build.id) + self.assertEqual(sum(sam_move.mapped("product_qty")), 4) + + mo_form = Form(production) + mo_form.qty_producing = 1 + production = mo_form.save() + + action = production.button_mark_done() + backorder = Form(self.env['mrp.production.backorder'].with_context(**action['context'])) + backorder.save().action_backorder() + + mo_backorder = production.procurement_group_id.mrp_production_ids[-1] + self.assertEqual(mo_backorder.delivery_count, 2) + + pbm_move |= mo_backorder.move_raw_ids.move_orig_ids + self.assertEqual(sum(pbm_move.filtered(lambda m: m.product_id.id == product_to_use_1.id).mapped("product_qty")), 16) + self.assertEqual(sum(pbm_move.filtered(lambda m: m.product_id.id == product_to_use_2.id).mapped("product_qty")), 4) + + sam_move |= mo_backorder.move_finished_ids.move_orig_ids + self.assertEqual(sum(sam_move.mapped("product_qty")), 4) + + def test_tracking_backorder_series_lot_1(self): + """ Create a MO of 4 tracked products. all component is tracked by lots + Produce one by one with one bakorder for each until end. + """ + nb_product_todo = 4 + production, _, p_final, p1, p2 = self.generate_mo(qty_final=nb_product_todo, tracking_final='lot', tracking_base_1='lot', tracking_base_2='lot') + lot_final = self.env['stock.production.lot'].create({ + 'name': 'lot_final', + 'product_id': p_final.id, + 'company_id': self.env.company.id, + }) + lot_1 = self.env['stock.production.lot'].create({ + 'name': 'lot_consumed_1', + 'product_id': p1.id, + 'company_id': self.env.company.id, + }) + lot_2 = self.env['stock.production.lot'].create({ + 'name': 'lot_consumed_2', + 'product_id': p2.id, + 'company_id': self.env.company.id, + }) + + self.env['stock.quant']._update_available_quantity(p1, self.stock_location, nb_product_todo*4, lot_id=lot_1) + self.env['stock.quant']._update_available_quantity(p2, self.stock_location, nb_product_todo, lot_id=lot_2) + + production.action_assign() + active_production = production + for i in range(nb_product_todo): + + details_operation_form = Form(active_production.move_raw_ids.filtered(lambda m: m.product_id == p1), view=self.env.ref('stock.view_stock_move_operations')) + with details_operation_form.move_line_ids.edit(0) as ml: + ml.qty_done = 4 + ml.lot_id = lot_1 + details_operation_form.save() + details_operation_form = Form(active_production.move_raw_ids.filtered(lambda m: m.product_id == p2), view=self.env.ref('stock.view_stock_move_operations')) + with details_operation_form.move_line_ids.edit(0) as ml: + ml.qty_done = 1 + ml.lot_id = lot_2 + details_operation_form.save() + + production_form = Form(active_production) + production_form.qty_producing = 1 + production_form.lot_producing_id = lot_final + active_production = production_form.save() + + active_production.button_mark_done() + if i + 1 != nb_product_todo: # If last MO, don't make a backorder + action = active_production.button_mark_done() + backorder = Form(self.env['mrp.production.backorder'].with_context(**action['context'])) + backorder.save().action_backorder() + active_production = active_production.procurement_group_id.mrp_production_ids[-1] + + self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location, lot_id=lot_final), nb_product_todo, f'You should have the {nb_product_todo} final product in stock') + self.assertEqual(len(production.procurement_group_id.mrp_production_ids), nb_product_todo) + + def test_tracking_backorder_series_serial_1(self): + """ Create a MO of 4 tracked products (serial) with pbm_sam. + all component is tracked by serial + Produce one by one with one bakorder for each until end. + """ + nb_product_todo = 4 + production, _, p_final, p1, p2 = self.generate_mo(qty_final=nb_product_todo, tracking_final='serial', tracking_base_1='serial', tracking_base_2='serial', qty_base_1=1) + serials_final, serials_p1, serials_p2 = [], [], [] + for i in range(nb_product_todo): + serials_final.append(self.env['stock.production.lot'].create({ + 'name': f'lot_final_{i}', + 'product_id': p_final.id, + 'company_id': self.env.company.id, + })) + serials_p1.append(self.env['stock.production.lot'].create({ + 'name': f'lot_consumed_1_{i}', + 'product_id': p1.id, + 'company_id': self.env.company.id, + })) + serials_p2.append(self.env['stock.production.lot'].create({ + 'name': f'lot_consumed_2_{i}', + 'product_id': p2.id, + 'company_id': self.env.company.id, + })) + self.env['stock.quant']._update_available_quantity(p1, self.stock_location, 1, lot_id=serials_p1[-1]) + self.env['stock.quant']._update_available_quantity(p2, self.stock_location, 1, lot_id=serials_p2[-1]) + + production.action_assign() + active_production = production + for i in range(nb_product_todo): + + details_operation_form = Form(active_production.move_raw_ids.filtered(lambda m: m.product_id == p1), view=self.env.ref('stock.view_stock_move_operations')) + with details_operation_form.move_line_ids.edit(0) as ml: + ml.qty_done = 1 + ml.lot_id = serials_p1[i] + details_operation_form.save() + details_operation_form = Form(active_production.move_raw_ids.filtered(lambda m: m.product_id == p2), view=self.env.ref('stock.view_stock_move_operations')) + with details_operation_form.move_line_ids.edit(0) as ml: + ml.qty_done = 1 + ml.lot_id = serials_p2[i] + details_operation_form.save() + + production_form = Form(active_production) + production_form.qty_producing = 1 + production_form.lot_producing_id = serials_final[i] + active_production = production_form.save() + + active_production.button_mark_done() + if i + 1 != nb_product_todo: # If last MO, don't make a backorder + action = active_production.button_mark_done() + backorder = Form(self.env['mrp.production.backorder'].with_context(**action['context'])) + backorder.save().action_backorder() + active_production = active_production.procurement_group_id.mrp_production_ids[-1] + + self.assertEqual(self.env['stock.quant']._get_available_quantity(p_final, self.stock_location), nb_product_todo, f'You should have the {nb_product_todo} final product in stock') + self.assertEqual(len(production.procurement_group_id.mrp_production_ids), nb_product_todo) + + def test_backorder_name(self): + def produce_one(mo): + mo_form = Form(mo) + mo_form.qty_producing = 1 + mo = mo_form.save() + action = mo.button_mark_done() + backorder = Form(self.env['mrp.production.backorder'].with_context(**action['context'])) + backorder.save().action_backorder() + return mo.procurement_group_id.mrp_production_ids[-1] + + default_picking_type_id = self.env['mrp.production']._get_default_picking_type() + default_picking_type = self.env['stock.picking.type'].browse(default_picking_type_id) + mo_sequence = default_picking_type.sequence_id + + mo_sequence.prefix = "WH-MO-" + initial_mo_name = mo_sequence.prefix + str(mo_sequence.number_next_actual).zfill(mo_sequence.padding) + + production = self.generate_mo(qty_final=5)[0] + self.assertEqual(production.name, initial_mo_name) + + backorder = produce_one(production) + self.assertEqual(production.name, initial_mo_name + "-001") + self.assertEqual(backorder.name, initial_mo_name + "-002") + + backorder.backorder_sequence = 998 + + for seq in [998, 999, 1000]: + new_backorder = produce_one(backorder) + self.assertEqual(backorder.name, initial_mo_name + "-" + str(seq)) + self.assertEqual(new_backorder.name, initial_mo_name + "-" + str(seq + 1)) + backorder = new_backorder + + +class TestMrpWorkorderBackorder(SavepointCase): + @classmethod + def setUpClass(cls): + super(TestMrpWorkorderBackorder, cls).setUpClass() + cls.uom_unit = cls.env['uom.uom'].search([ + ('category_id', '=', cls.env.ref('uom.product_uom_categ_unit').id), + ('uom_type', '=', 'reference') + ], limit=1) + cls.finished1 = cls.env['product.product'].create({ + 'name': 'finished1', + 'type': 'product', + }) + cls.compfinished1 = cls.env['product.product'].create({ + 'name': 'compfinished1', + 'type': 'product', + }) + cls.compfinished2 = cls.env['product.product'].create({ + 'name': 'compfinished2', + 'type': 'product', + }) + cls.workcenter1 = cls.env['mrp.workcenter'].create({ + 'name': 'workcenter1', + }) + cls.workcenter2 = cls.env['mrp.workcenter'].create({ + 'name': 'workcenter2', + }) + + cls.bom_finished1 = cls.env['mrp.bom'].create({ + 'product_id': cls.finished1.id, + 'product_tmpl_id': cls.finished1.product_tmpl_id.id, + 'product_uom_id': cls.uom_unit.id, + 'product_qty': 1, + 'consumption': 'flexible', + 'type': 'normal', + 'bom_line_ids': [ + (0, 0, {'product_id': cls.compfinished1.id, 'product_qty': 1}), + (0, 0, {'product_id': cls.compfinished2.id, 'product_qty': 1}), + ], + 'operation_ids': [ + (0, 0, {'sequence': 1, 'name': 'finished operation 1', 'workcenter_id': cls.workcenter1.id}), + (0, 0, {'sequence': 2, 'name': 'finished operation 2', 'workcenter_id': cls.workcenter2.id}), + ], + }) + cls.bom_finished1.bom_line_ids[0].operation_id = cls.bom_finished1.operation_ids[0].id + cls.bom_finished1.bom_line_ids[1].operation_id = cls.bom_finished1.operation_ids[1].id |
