summaryrefslogtreecommitdiff
path: root/addons/mrp/tests/test_procurement.py
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/mrp/tests/test_procurement.py
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/mrp/tests/test_procurement.py')
-rw-r--r--addons/mrp/tests/test_procurement.py598
1 files changed, 598 insertions, 0 deletions
diff --git a/addons/mrp/tests/test_procurement.py b/addons/mrp/tests/test_procurement.py
new file mode 100644
index 00000000..b7da5255
--- /dev/null
+++ b/addons/mrp/tests/test_procurement.py
@@ -0,0 +1,598 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+from datetime import datetime, timedelta
+
+from odoo import fields
+from odoo.tests import Form
+from odoo.addons.mrp.tests.common import TestMrpCommon
+from odoo.exceptions import UserError
+from odoo.tools import mute_logger
+
+
+class TestProcurement(TestMrpCommon):
+
+ def test_procurement(self):
+ """This test case when create production order check procurement is create"""
+ # Update BOM
+ self.bom_3.bom_line_ids.filtered(lambda x: x.product_id == self.product_5).unlink()
+ self.bom_1.bom_line_ids.filtered(lambda x: x.product_id == self.product_1).unlink()
+ # Update route
+ self.warehouse = self.env.ref('stock.warehouse0')
+ self.warehouse.mto_pull_id.route_id.active = True
+ route_manufacture = self.warehouse.manufacture_pull_id.route_id.id
+ route_mto = self.warehouse.mto_pull_id.route_id.id
+ self.product_4.write({'route_ids': [(6, 0, [route_manufacture, route_mto])]})
+
+ # Create production order
+ # -------------------------
+ # Product6 Unit 24
+ # Product4 8 Dozen
+ # Product2 12 Unit
+ # -----------------------
+
+ production_form = Form(self.env['mrp.production'])
+ production_form.product_id = self.product_6
+ production_form.bom_id = self.bom_3
+ production_form.product_qty = 24
+ production_form.product_uom_id = self.product_6.uom_id
+ production_product_6 = production_form.save()
+ production_product_6.action_confirm()
+ production_product_6.action_assign()
+
+ # check production state is Confirmed
+ self.assertEqual(production_product_6.state, 'confirmed')
+
+ # Check procurement for product 4 created or not.
+ # Check it created a purchase order
+
+ move_raw_product4 = production_product_6.move_raw_ids.filtered(lambda x: x.product_id == self.product_4)
+ produce_product_4 = self.env['mrp.production'].search([('product_id', '=', self.product_4.id),
+ ('move_dest_ids', '=', move_raw_product4[0].id)])
+ # produce product
+ self.assertEqual(produce_product_4.reservation_state, 'confirmed', "Consume material not available")
+
+ # Create production order
+ # -------------------------
+ # Product 4 96 Unit
+ # Product2 48 Unit
+ # ---------------------
+ # Update Inventory
+ self.env['stock.quant'].with_context(inventory_mode=True).create({
+ 'product_id': self.product_2.id,
+ 'inventory_quantity': 48,
+ 'location_id': self.warehouse.lot_stock_id.id,
+ })
+ produce_product_4.action_assign()
+ self.assertEqual(produce_product_4.product_qty, 8, "Wrong quantity of finish product.")
+ self.assertEqual(produce_product_4.product_uom_id, self.uom_dozen, "Wrong quantity of finish product.")
+ self.assertEqual(produce_product_4.reservation_state, 'assigned', "Consume material not available")
+
+ # produce product4
+ # ---------------
+
+ mo_form = Form(produce_product_4)
+ mo_form.qty_producing = produce_product_4.product_qty
+ produce_product_4 = mo_form.save()
+ # Check procurement and Production state for product 4.
+ produce_product_4.button_mark_done()
+ self.assertEqual(produce_product_4.state, 'done', 'Production order should be in state done')
+
+ # Produce product 6
+ # ------------------
+
+ # Update Inventory
+ self.env['stock.quant'].with_context(inventory_mode=True).create({
+ 'product_id': self.product_2.id,
+ 'inventory_quantity': 12,
+ 'location_id': self.warehouse.lot_stock_id.id,
+ })
+ production_product_6.action_assign()
+
+ # ------------------------------------
+
+ self.assertEqual(production_product_6.reservation_state, 'assigned', "Consume material not available")
+ mo_form = Form(production_product_6)
+ mo_form.qty_producing = production_product_6.product_qty
+ production_product_6 = mo_form.save()
+ # Check procurement and Production state for product 6.
+ production_product_6.button_mark_done()
+ self.assertEqual(production_product_6.state, 'done', 'Production order should be in state done')
+ self.assertEqual(self.product_6.qty_available, 24, 'Wrong quantity available of finished product.')
+
+ def test_procurement_2(self):
+ """Check that a manufacturing order create the right procurements when the route are set on
+ a parent category of a product"""
+ # find a child category id
+ all_categ_id = self.env['product.category'].search([('parent_id', '=', None)], limit=1)
+ child_categ_id = self.env['product.category'].search([('parent_id', '=', all_categ_id.id)], limit=1)
+
+ # set the product of `self.bom_1` to this child category
+ for bom_line_id in self.bom_1.bom_line_ids:
+ # check that no routes are defined on the product
+ self.assertEqual(len(bom_line_id.product_id.route_ids), 0)
+ # set the category of the product to a child category
+ bom_line_id.product_id.categ_id = child_categ_id
+
+ # set the MTO route to the parent category (all)
+ self.warehouse = self.env.ref('stock.warehouse0')
+ mto_route = self.warehouse.mto_pull_id.route_id
+ mto_route.active = True
+ mto_route.product_categ_selectable = True
+ all_categ_id.write({'route_ids': [(6, 0, [mto_route.id])]})
+
+ # create MO, but check it raises error as components are in make to order and not everyone has
+ with self.assertRaises(UserError):
+ production_form = Form(self.env['mrp.production'])
+ production_form.product_id = self.product_4
+ production_form.product_uom_id = self.product_4.uom_id
+ production_form.product_qty = 1
+ production_product_4 = production_form.save()
+ production_product_4.action_confirm()
+
+ def test_procurement_4(self):
+ warehouse = self.env['stock.warehouse'].search([], limit=1)
+ product_A = self.env['product.product'].create({
+ 'name': 'productA',
+ 'type': 'product',
+ 'route_ids': [(4, self.ref('mrp.route_warehouse0_manufacture'))]
+ })
+ product_B = self.env['product.product'].create({
+ 'name': 'productB',
+ 'type': 'product',
+ 'route_ids': [(4, self.ref('mrp.route_warehouse0_manufacture'))]
+ })
+ product_C = self.env['product.product'].create({
+ 'name': 'productC',
+ 'type': 'product',
+ })
+ product_route = self.env['stock.location.route'].create({
+ 'name': 'Stock -> output route',
+ 'product_selectable': True,
+ 'rule_ids': [(0, 0, {
+ 'name': 'Stock -> output rule',
+ 'action': 'pull',
+ 'picking_type_id': self.ref('stock.picking_type_internal'),
+ 'location_src_id': self.ref('stock.stock_location_stock'),
+ 'location_id': self.ref('stock.stock_location_output'),
+ })],
+ })
+
+ # Set this route on `product.product_product_3`
+ product_C.write({
+ 'route_ids': [(4, product_route.id)]
+ })
+
+ bom_A = self.env['mrp.bom'].create({
+ 'product_id': product_A.id,
+ 'product_tmpl_id': product_A.product_tmpl_id.id,
+ 'product_uom_id': self.uom_unit.id,
+ 'product_qty': 1.0,
+ 'type': 'normal',
+ 'bom_line_ids': [
+ (0, 0, {'product_id': product_B.id, 'product_qty': 2.0})
+ ]})
+
+ self.env['stock.warehouse.orderpoint'].create({
+ 'name': 'A RR',
+ 'location_id': warehouse.lot_stock_id.id,
+ 'product_id': product_A.id,
+ 'product_min_qty': 10,
+ 'product_max_qty': 100,
+ })
+
+ bom_B = self.env['mrp.bom'].create({
+ 'product_id': product_B.id,
+ 'product_tmpl_id': product_B.product_tmpl_id.id,
+ 'product_uom_id': self.uom_unit.id,
+ 'product_qty': 1.0,
+ 'type': 'normal',
+ 'bom_line_ids': [
+ (0, 0, {'product_id': product_C.id, 'product_qty': 1.0})
+ ]})
+
+ self.env['stock.warehouse.orderpoint'].create({
+ 'name': 'B RR',
+ 'location_id': warehouse.lot_stock_id.id,
+ 'product_id': product_B.id,
+ 'product_min_qty': 20,
+ 'product_max_qty': 200,
+ })
+
+ self.env['stock.warehouse.orderpoint'].create({
+ 'name': 'C RR',
+ 'location_id': warehouse.lot_stock_id.id,
+ 'product_id': product_C.id,
+ 'product_min_qty': 20,
+ 'product_max_qty': 200,
+ })
+
+ with mute_logger('odoo.addons.stock.models.procurement'):
+ self.env['procurement.group'].run_scheduler()
+
+ production_A = self.env['mrp.production'].search([
+ ('product_id', '=', product_A.id),
+ ('state', '=', 'confirmed')
+ ])
+ self.assertEqual(production_A.product_uom_qty, 100, "100 units of A should be scheduled for production")
+ production_B = self.env['mrp.production'].search([
+ ('product_id', '=', product_B.id),
+ ('state', '=', 'confirmed')
+ ])
+ self.assertEqual(sum(production_B.mapped('product_uom_qty')), 400, "400 units of B should be scheduled for production")
+
+ def test_procurement_3(self):
+ warehouse = self.env['stock.warehouse'].search([], limit=1)
+ warehouse.write({'reception_steps': 'three_steps'})
+ warehouse.mto_pull_id.route_id.active = True
+ self.env['stock.location']._parent_store_compute()
+ warehouse.reception_route_id.rule_ids.filtered(
+ lambda p: p.location_src_id == warehouse.wh_input_stock_loc_id and
+ p.location_id == warehouse.wh_qc_stock_loc_id).write({
+ 'procure_method': 'make_to_stock'
+ })
+
+ finished_product = self.env['product.product'].create({
+ 'name': 'Finished Product',
+ 'type': 'product',
+ })
+ component = self.env['product.product'].create({
+ 'name': 'Component',
+ 'type': 'product',
+ 'route_ids': [(4, warehouse.mto_pull_id.route_id.id)]
+ })
+ self.env['stock.quant']._update_available_quantity(component, warehouse.wh_input_stock_loc_id, 100)
+ bom = self.env['mrp.bom'].create({
+ 'product_id': finished_product.id,
+ 'product_tmpl_id': finished_product.product_tmpl_id.id,
+ 'product_uom_id': self.uom_unit.id,
+ 'product_qty': 1.0,
+ 'type': 'normal',
+ 'bom_line_ids': [
+ (0, 0, {'product_id': component.id, 'product_qty': 1.0})
+ ]})
+ mo_form = Form(self.env['mrp.production'])
+ mo_form.product_id = finished_product
+ mo_form.bom_id = bom
+ mo_form.product_qty = 5
+ mo_form.product_uom_id = finished_product.uom_id
+ mo_form.location_src_id = warehouse.lot_stock_id
+ mo = mo_form.save()
+ mo.action_confirm()
+ pickings = self.env['stock.picking'].search([('product_id', '=', component.id)])
+ self.assertEqual(len(pickings), 2.0)
+ picking_input_to_qc = pickings.filtered(lambda p: p.location_id == warehouse.wh_input_stock_loc_id)
+ picking_qc_to_stock = pickings - picking_input_to_qc
+ self.assertTrue(picking_input_to_qc)
+ self.assertTrue(picking_qc_to_stock)
+ picking_input_to_qc.action_assign()
+ self.assertEqual(picking_input_to_qc.state, 'assigned')
+ picking_input_to_qc.move_line_ids.write({'qty_done': 5.0})
+ picking_input_to_qc._action_done()
+ picking_qc_to_stock.action_assign()
+ self.assertEqual(picking_qc_to_stock.state, 'assigned')
+ picking_qc_to_stock.move_line_ids.write({'qty_done': 3.0})
+ picking_qc_to_stock.with_context(skip_backorder=True, picking_ids_not_to_backorder=picking_qc_to_stock.ids).button_validate()
+ self.assertEqual(picking_qc_to_stock.state, 'done')
+ mo.action_assign()
+ self.assertEqual(mo.move_raw_ids.reserved_availability, 3.0)
+ produce_form = Form(mo)
+ produce_form.qty_producing = 3.0
+ mo = produce_form.save()
+ self.assertEqual(mo.move_raw_ids.quantity_done, 3.0)
+ picking_qc_to_stock.move_line_ids.qty_done = 5.0
+ self.assertEqual(mo.move_raw_ids.reserved_availability, 5.0)
+ self.assertEqual(mo.move_raw_ids.quantity_done, 3.0)
+
+ def test_link_date_mo_moves(self):
+ """ Check link of shedule date for manufaturing with date stock move."""
+
+ # create a product with manufacture route
+ product_1 = self.env['product.product'].create({
+ 'name': 'AAA',
+ 'route_ids': [(4, self.ref('mrp.route_warehouse0_manufacture'))]
+ })
+
+ component_1 = self.env['product.product'].create({
+ 'name': 'component',
+ })
+
+ self.env['mrp.bom'].create({
+ 'product_id': product_1.id,
+ 'product_tmpl_id': product_1.product_tmpl_id.id,
+ 'product_uom_id': self.uom_unit.id,
+ 'product_qty': 1.0,
+ 'type': 'normal',
+ 'bom_line_ids': [
+ (0, 0, {'product_id': component_1.id, 'product_qty': 1}),
+ ]})
+
+ # create a move for product_1 from stock to output and reserve to trigger the
+ # rule
+ move_dest = self.env['stock.move'].create({
+ 'name': 'move_orig',
+ 'product_id': product_1.id,
+ 'product_uom': self.ref('uom.product_uom_unit'),
+ 'location_id': self.ref('stock.stock_location_stock'),
+ 'location_dest_id': self.ref('stock.stock_location_output'),
+ 'product_uom_qty': 10,
+ 'procure_method': 'make_to_order'
+ })
+
+ move_dest._action_confirm()
+ mo = self.env['mrp.production'].search([
+ ('product_id', '=', product_1.id),
+ ('state', '=', 'confirmed')
+ ])
+
+ self.assertAlmostEqual(mo.move_finished_ids.date, mo.move_raw_ids.date + timedelta(hours=1), delta=timedelta(seconds=1))
+
+ self.assertEqual(len(mo), 1, 'the manufacture order is not created')
+
+ mo_form = Form(mo)
+ self.assertEqual(mo_form.product_qty, 10, 'the quantity to produce is not good relative to the move')
+
+ mo = mo_form.save()
+
+ # Confirming mo create finished move
+ move_orig = self.env['stock.move'].search([
+ ('move_dest_ids', 'in', move_dest.ids)
+ ], limit=1)
+
+ self.assertEqual(len(move_orig), 1, 'the move orig is not created')
+ self.assertEqual(move_orig.product_qty, 10, 'the quantity to produce is not good relative to the move')
+
+ new_sheduled_date = fields.Datetime.to_datetime(mo.date_planned_start) + timedelta(days=5)
+ mo_form = Form(mo)
+ mo_form.date_planned_start = new_sheduled_date
+ mo = mo_form.save()
+
+ self.assertAlmostEqual(mo.move_raw_ids.date, mo.date_planned_start, delta=timedelta(seconds=1))
+ self.assertAlmostEqual(mo.move_finished_ids.date, mo.date_planned_finished, delta=timedelta(seconds=1))
+
+ def test_finished_move_cancellation(self):
+ """Check state of finished move on cancellation of raw moves. """
+ product_bottle = self.env['product.product'].create({
+ 'name': 'Plastic Bottle',
+ 'route_ids': [(4, self.ref('mrp.route_warehouse0_manufacture'))]
+ })
+
+ component_mold = self.env['product.product'].create({
+ 'name': 'Plastic Mold',
+ })
+
+ self.env['mrp.bom'].create({
+ 'product_id': product_bottle.id,
+ 'product_tmpl_id': product_bottle.product_tmpl_id.id,
+ 'product_uom_id': self.uom_unit.id,
+ 'product_qty': 1.0,
+ 'type': 'normal',
+ 'bom_line_ids': [
+ (0, 0, {'product_id': component_mold.id, 'product_qty': 1}),
+ ]})
+
+ move_dest = self.env['stock.move'].create({
+ 'name': 'move_bottle',
+ 'product_id': product_bottle.id,
+ 'product_uom': self.ref('uom.product_uom_unit'),
+ 'location_id': self.ref('stock.stock_location_stock'),
+ 'location_dest_id': self.ref('stock.stock_location_output'),
+ 'product_uom_qty': 10,
+ 'procure_method': 'make_to_order',
+ })
+
+ move_dest._action_confirm()
+ mo = self.env['mrp.production'].search([
+ ('product_id', '=', product_bottle.id),
+ ('state', '=', 'confirmed')
+ ])
+ mo.move_raw_ids[0]._action_cancel()
+ self.assertEqual(mo.state, 'cancel', 'Manufacturing order should be cancelled.')
+ self.assertEqual(mo.move_finished_ids[0].state, 'cancel', 'Finished move should be cancelled if mo is cancelled.')
+ self.assertEqual(mo.move_dest_ids[0].state, 'waiting', 'Destination move should not be cancelled if prapogation cancel is False on manufacturing rule.')
+
+ def test_procurement_with_empty_bom(self):
+ """Ensure that a procurement request using a product with an empty BoM
+ will create a MO in draft state that could be completed afterwards.
+ """
+ self.warehouse = self.env.ref('stock.warehouse0')
+ route_manufacture = self.warehouse.manufacture_pull_id.route_id.id
+ route_mto = self.warehouse.mto_pull_id.route_id.id
+ product = self.env['product.product'].create({
+ 'name': 'Clafoutis',
+ 'route_ids': [(6, 0, [route_manufacture, route_mto])]
+ })
+ self.env['mrp.bom'].create({
+ 'product_id': product.id,
+ 'product_tmpl_id': product.product_tmpl_id.id,
+ 'product_uom_id': self.uom_unit.id,
+ 'product_qty': 1.0,
+ 'type': 'normal',
+ })
+ move_dest = self.env['stock.move'].create({
+ 'name': 'Customer MTO Move',
+ 'product_id': product.id,
+ 'product_uom': self.ref('uom.product_uom_unit'),
+ 'location_id': self.ref('stock.stock_location_stock'),
+ 'location_dest_id': self.ref('stock.stock_location_output'),
+ 'product_uom_qty': 10,
+ 'procure_method': 'make_to_order',
+ })
+ move_dest._action_confirm()
+
+ production = self.env['mrp.production'].search([('product_id', '=', product.id)])
+ self.assertTrue(production)
+ self.assertFalse(production.move_raw_ids)
+ self.assertEqual(production.state, 'draft')
+
+ comp1 = self.env['product.product'].create({
+ 'name': 'egg',
+ })
+ move_values = production._get_move_raw_values(comp1, 40.0, self.env.ref('uom.product_uom_unit'))
+ self.env['stock.move'].create(move_values)
+
+ production.action_confirm()
+ produce_form = Form(production)
+ produce_form.qty_producing = production.product_qty
+ production = produce_form.save()
+ production.button_mark_done()
+
+ move_dest._action_assign()
+ self.assertEqual(move_dest.reserved_availability, 10.0)
+
+ def test_auto_assign(self):
+ """ When auto reordering rule exists, check for when:
+ 1. There is not enough of a manufactured product to assign (reserve for) a picking => auto-create 1st MO
+ 2. There is not enough of a manufactured component to assign the created MO => auto-create 2nd MO
+ 3. Add an extra manufactured component (not in stock) to 1st MO => auto-create 3rd MO
+ 4. When 2nd MO is completed => auto-assign to 1st MO
+ 5. When 1st MO is completed => auto-assign to picking """
+
+ self.warehouse = self.env.ref('stock.warehouse0')
+ route_manufacture = self.warehouse.manufacture_pull_id.route_id
+
+ product_1 = self.env['product.product'].create({
+ 'name': 'Cake',
+ 'type': 'product',
+ 'route_ids': [(6, 0, [route_manufacture.id])]
+ })
+ product_2 = self.env['product.product'].create({
+ 'name': 'Cake Mix',
+ 'type': 'product',
+ 'route_ids': [(6, 0, [route_manufacture.id])]
+ })
+ product_3 = self.env['product.product'].create({
+ 'name': 'Flour',
+ 'type': 'consu',
+ })
+
+ self.env['mrp.bom'].create({
+ 'product_id': product_1.id,
+ 'product_tmpl_id': product_1.product_tmpl_id.id,
+ 'product_uom_id': self.uom_unit.id,
+ 'product_qty': 1,
+ 'consumption': 'flexible',
+ 'type': 'normal',
+ 'bom_line_ids': [
+ (0, 0, {'product_id': product_2.id, 'product_qty': 1}),
+ ]})
+
+ self.env['mrp.bom'].create({
+ 'product_id': product_2.id,
+ 'product_tmpl_id': product_2.product_tmpl_id.id,
+ 'product_uom_id': self.uom_unit.id,
+ 'product_qty': 1,
+ 'type': 'normal',
+ 'bom_line_ids': [
+ (0, 0, {'product_id': product_3.id, 'product_qty': 1}),
+ ]})
+
+ # extra manufactured component added to 1st MO after it is already confirmed
+ product_4 = self.env['product.product'].create({
+ 'name': 'Flavor Enchancer',
+ 'type': 'product',
+ 'route_ids': [(6, 0, [route_manufacture.id])]
+ })
+ product_5 = self.env['product.product'].create({
+ 'name': 'MSG',
+ 'type': 'consu',
+ })
+
+ self.env['mrp.bom'].create({
+ 'product_id': product_4.id,
+ 'product_tmpl_id': product_4.product_tmpl_id.id,
+ 'product_uom_id': self.uom_unit.id,
+ 'product_qty': 1,
+ 'type': 'normal',
+ 'bom_line_ids': [
+ (0, 0, {'product_id': product_5.id, 'product_qty': 1}),
+ ]})
+
+ # setup auto orderpoints (reordering rules)
+ self.env['stock.warehouse.orderpoint'].create({
+ 'name': 'Cake RR',
+ 'location_id': self.warehouse.lot_stock_id.id,
+ 'product_id': product_1.id,
+ 'product_min_qty': 0,
+ 'product_max_qty': 5,
+ })
+
+ self.env['stock.warehouse.orderpoint'].create({
+ 'name': 'Cake Mix RR',
+ 'location_id': self.warehouse.lot_stock_id.id,
+ 'product_id': product_2.id,
+ 'product_min_qty': 0,
+ 'product_max_qty': 5,
+ })
+
+ self.env['stock.warehouse.orderpoint'].create({
+ 'name': 'Flavor Enchancer RR',
+ 'location_id': self.warehouse.lot_stock_id.id,
+ 'product_id': product_4.id,
+ 'product_min_qty': 0,
+ 'product_max_qty': 5,
+ })
+
+ # create picking output to trigger creating MO for reordering product_1
+ pick_output = self.env['stock.picking'].create({
+ 'name': 'Cake Delivery Order',
+ 'picking_type_id': self.ref('stock.picking_type_out'),
+ 'location_id': self.warehouse.lot_stock_id.id,
+ 'location_dest_id': self.ref('stock.stock_location_customers'),
+ 'move_lines': [(0, 0, {
+ 'name': '/',
+ 'product_id': product_1.id,
+ 'product_uom': product_1.uom_id.id,
+ 'product_uom_qty': 10.00,
+ 'procure_method': 'make_to_stock',
+ })],
+ })
+ pick_output.action_confirm() # should trigger orderpoint to create and confirm 1st MO
+ pick_output.action_assign()
+
+ mo = self.env['mrp.production'].search([
+ ('product_id', '=', product_1.id),
+ ('state', '=', 'confirmed')
+ ])
+
+ self.assertEqual(len(mo), 1, "Manufacture order was not automatically created")
+ mo.action_assign()
+ self.assertEqual(mo.move_raw_ids.reserved_availability, 0, "No components should be reserved yet")
+ self.assertEqual(mo.product_qty, 15, "Quantity to produce should be picking demand + reordering rule max qty")
+
+ # 2nd MO for product_2 should have been created and confirmed when 1st MO for product_1 was confirmed
+ mo2 = self.env['mrp.production'].search([
+ ('product_id', '=', product_2.id),
+ ('state', '=', 'confirmed')
+ ])
+
+ self.assertEqual(len(mo2), 1, 'Second manufacture order was not created')
+ self.assertEqual(mo2.product_qty, 20, "Quantity to produce should be MO's 'to consume' qty + reordering rule max qty")
+ mo2_form = Form(mo2)
+ mo2_form.qty_producing = 20
+ mo2 = mo2_form.save()
+ mo2.button_mark_done()
+
+ self.assertEqual(mo.move_raw_ids.reserved_availability, 15, "Components should have been auto-reserved")
+
+ # add new component to 1st MO
+ mo_form = Form(mo)
+ with mo_form.move_raw_ids.new() as line:
+ line.product_id = product_4
+ line.product_uom_qty = 1
+ mo_form.save() # should trigger orderpoint to create and confirm 3rd MO
+
+ mo3 = self.env['mrp.production'].search([
+ ('product_id', '=', product_4.id),
+ ('state', '=', 'confirmed')
+ ])
+
+ self.assertEqual(len(mo3), 1, 'Third manufacture order for added component was not created')
+ self.assertEqual(mo3.product_qty, 6, "Quantity to produce should be 1 + reordering rule max qty")
+
+ mo_form = Form(mo)
+ mo.move_raw_ids.quantity_done = 15
+ mo_form.qty_producing = 15
+ mo = mo_form.save()
+ mo.button_mark_done()
+
+ self.assertEqual(pick_output.move_ids_without_package.reserved_availability, 10, "Completed products should have been auto-reserved in picking")