19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:31:47 +01:00
parent accf5918df
commit 6e65e8c877
688 changed files with 225434 additions and 199401 deletions

View file

@ -12,15 +12,19 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
def setUpClass(cls):
super().setUpClass()
# Required for `uom_id` to be visible in the view
cls.env.user.groups_id += cls.env.ref('uom.group_uom')
cls.env.user.group_ids += cls.env.ref('uom.group_uom')
cls.env.user.group_ids += cls.env.ref('product.group_product_variant')
# Required for `manufacture_steps` to be visible in the view
cls.env.user.groups_id += cls.env.ref('stock.group_adv_location')
cls.env.user.group_ids += cls.env.ref('stock.group_adv_location')
# Required for `product_id` to be visible in the view
cls.env.user.group_ids += cls.env.ref('product.group_product_variant')
# Create warehouse
cls.customer_location = cls.env['ir.model.data']._xmlid_to_res_id('stock.stock_location_customers')
warehouse_form = Form(cls.env['stock.warehouse'])
warehouse_form.name = 'Test Warehouse'
warehouse_form.code = 'TWH'
cls.warehouse = warehouse_form.save()
# Enable MTO
cls.warehouse.mto_pull_id.route_id.active = True
cls.uom_unit = cls.env.ref('uom.product_uom_unit')
@ -28,19 +32,16 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
product_form = Form(cls.env['product.product'])
product_form.name = 'Stick'
product_form.uom_id = cls.uom_unit
product_form.uom_po_id = cls.uom_unit
product_form.detailed_type = 'product'
product_form.is_storable = True
product_form.route_ids.clear()
product_form.route_ids.add(cls.warehouse.manufacture_pull_id.route_id)
product_form.route_ids.add(cls.warehouse.mto_pull_id.route_id)
cls.finished_product = product_form.save()
# Create raw product for manufactured product
product_form = Form(cls.env['product.product'])
product_form.name = 'Raw Stick'
product_form.detailed_type = 'product'
product_form.is_storable = True
product_form.uom_id = cls.uom_unit
product_form.uom_po_id = cls.uom_unit
cls.raw_product = product_form.save()
# Create bom for manufactured product
@ -85,12 +86,53 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
self.assertEqual(self.warehouse.manufacture_pull_id.location_dest_id.id, self.warehouse.lot_stock_id.id)
def test_02_warehouse_twostep_manufacturing(self):
""" Warehouse testing for picking ans store after manufacturing """
""" Warehouse testing for picking and store after manufacturing """
with Form(self.warehouse) as warehouse:
warehouse.manufacture_steps = 'pbm_sam'
self._check_location_and_routes()
self.assertEqual(len(self.warehouse.pbm_route_id.rule_ids), 3)
self.assertEqual(self.warehouse.manufacture_pull_id.location_dest_id.id, self.warehouse.sam_loc_id.id)
self.assertEqual(self.warehouse.manufacture_pull_id.location_dest_id.id, self.warehouse.lot_stock_id.id)
def test_manufacturing_2_steps_sublocation(self):
"""Check having a production order taking stock in a child location of pre prod
create correctly a 2 steps manufacturing even with only one mto rule from pre-pro to
production. """
self.warehouse.manufacture_steps = 'pbm'
pre_1, pre_2 = self.env['stock.location'].create([{
'name': name,
'location_id': self.warehouse.pbm_loc_id.id,
'usage': 'internal'
} for name in ('Pre 1', 'Pre 2')])
# create 2 picking type having 2 different pre-prod location
pick_1 = self.warehouse.manu_type_id.copy({
'sequence_code': 'PRE1',
'default_location_src_id': pre_1.id,
})
pick_2 = self.warehouse.manu_type_id.copy({
'sequence_code': 'PRE2',
'default_location_src_id': pre_2.id,
})
production_form = Form(self.env['mrp.production'])
production_form.picking_type_id = pick_1
production_form.product_id = self.finished_product
production = production_form.save()
production.action_confirm()
# check that picking is created
pick = production.picking_ids
self.assertEqual(pick.location_id, self.warehouse.lot_stock_id)
self.assertEqual(pick.location_dest_id, pre_1)
production_form = Form(self.env['mrp.production'])
production_form.picking_type_id = pick_2
production_form.product_id = self.finished_product
production = production_form.save()
production.action_confirm()
# check that picking is created
pick = production.picking_ids
self.assertEqual(pick.location_id, self.warehouse.lot_stock_id)
self.assertEqual(pick.location_dest_id, pre_2)
def test_manufacturing_3_steps(self):
""" Test MO/picking before manufacturing/picking after manufacturing
@ -121,6 +163,7 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
self.assertEqual(len(move_finished_ids), 1)
self.assertEqual(move_finished_ids.product_id, self.finished_product)
self.assertEqual(move_finished_ids.picking_type_id, self.warehouse.manu_type_id)
production.button_mark_done()
sam_move = move_finished_ids.move_dest_ids
self.assertEqual(len(sam_move), 1)
self.assertEqual(sam_move.location_id, self.warehouse.sam_loc_id)
@ -137,24 +180,24 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
"""
with Form(self.warehouse) as warehouse:
warehouse.manufacture_steps = 'pbm_sam'
warehouse.delivery_steps = 'pick_pack_ship'
self.warehouse.flush_model()
self.env.ref('stock.route_warehouse0_mto').active = True
self.route_mto.active = True
self.env['stock.quant']._update_available_quantity(self.raw_product, self.warehouse.lot_stock_id, 4.0)
picking_customer = self.env['stock.picking'].create({
'location_id': self.warehouse.wh_output_stock_loc_id.id,
'location_dest_id': self.customer_location,
'location_dest_id': self.customer_location.id,
'partner_id': self.env['ir.model.data']._xmlid_to_res_id('base.res_partner_4'),
'picking_type_id': self.warehouse.out_type_id.id,
'state': 'draft',
})
self.env['stock.move'].create({
'name': self.finished_product.name,
'product_id': self.finished_product.id,
'product_uom_qty': 2,
'product_uom': self.uom_unit.id,
'picking_id': picking_customer.id,
'location_id': self.warehouse.wh_output_stock_loc_id.id,
'location_dest_id': self.customer_location,
'location_id': self.warehouse.lot_stock_id.id,
'location_dest_id': self.customer_location.id,
'procure_method': 'make_to_order',
'origin': 'SOURCEDOCUMENT',
'state': 'draft',
@ -179,14 +222,12 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
]).picking_id
self.assertTrue(picking_stock_preprod)
self.assertTrue(picking_stock_postprod)
self.assertFalse(picking_stock_postprod)
self.assertEqual(picking_stock_preprod.state, 'assigned')
self.assertEqual(picking_stock_postprod.state, 'waiting')
self.assertEqual(picking_stock_preprod.origin, production_order.name, 'The pre-prod origin should be the MO name')
self.assertEqual(picking_stock_postprod.origin, 'SOURCEDOCUMENT', 'The post-prod origin should be the SO name')
picking_stock_preprod.action_assign()
picking_stock_preprod.move_line_ids.qty_done = 4
picking_stock_preprod.move_ids.write({'quantity': 4, 'picked': True})
picking_stock_preprod._action_done()
self.assertFalse(sum(self.env['stock.quant']._gather(self.raw_product, self.warehouse.lot_stock_id).mapped('quantity')))
@ -194,7 +235,6 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
production_order.action_assign()
self.assertEqual(production_order.reservation_state, 'assigned')
self.assertEqual(picking_stock_postprod.state, 'waiting')
produce_form = Form(production_order)
produce_form.qty_producing = production_order.product_qty
@ -203,15 +243,16 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
self.assertFalse(sum(self.env['stock.quant']._gather(self.raw_product, self.warehouse.pbm_loc_id).mapped('quantity')))
picking_stock_postprod = self.env['stock.move'].search([
('product_id', '=', self.finished_product.id),
('location_id', '=', self.warehouse.sam_loc_id.id),
('location_dest_id', '=', self.warehouse.lot_stock_id.id),
('picking_type_id', '=', self.warehouse.sam_type_id.id)
]).picking_id
self.assertTrue(picking_stock_postprod)
self.assertEqual(picking_stock_postprod.state, 'assigned')
picking_stock_pick = self.env['stock.move'].search([
('product_id', '=', self.finished_product.id),
('location_id', '=', self.warehouse.lot_stock_id.id),
('location_dest_id', '=', self.warehouse.wh_pack_stock_loc_id.id),
('picking_type_id', '=', self.warehouse.pick_type_id.id)
]).picking_id
self.assertEqual(picking_stock_pick.move_ids.move_orig_ids.picking_id, picking_stock_postprod)
self.assertEqual(picking_customer.move_ids.move_orig_ids.picking_id, picking_stock_postprod)
def test_cancel_propagation(self):
""" Test cancelling moves in a 'picking before
@ -223,18 +264,18 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
self.env['stock.quant']._update_available_quantity(self.raw_product, self.warehouse.lot_stock_id, 4.0)
picking_customer = self.env['stock.picking'].create({
'location_id': self.warehouse.lot_stock_id.id,
'location_dest_id': self.customer_location,
'location_dest_id': self.customer_location.id,
'partner_id': self.env['ir.model.data']._xmlid_to_res_id('base.res_partner_4'),
'picking_type_id': self.warehouse.out_type_id.id,
'state': 'draft',
})
self.env['stock.move'].create({
'name': self.finished_product.name,
'product_id': self.finished_product.id,
'product_uom_qty': 2,
'picking_id': picking_customer.id,
'product_uom': self.uom_unit.id,
'location_id': self.warehouse.lot_stock_id.id,
'location_dest_id': self.customer_location,
'location_dest_id': self.customer_location.id,
'procure_method': 'make_to_order',
})
picking_customer.action_confirm()
@ -247,22 +288,13 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
('location_dest_id', '=', self.warehouse.pbm_loc_id.id),
('picking_type_id', '=', self.warehouse.pbm_type_id.id)
])
move_stock_postprod = self.env['stock.move'].search([
('product_id', '=', self.finished_product.id),
('location_id', '=', self.warehouse.sam_loc_id.id),
('location_dest_id', '=', self.warehouse.lot_stock_id.id),
('picking_type_id', '=', self.warehouse.sam_type_id.id)
])
self.assertTrue(move_stock_preprod)
self.assertTrue(move_stock_postprod)
self.assertEqual(move_stock_preprod.state, 'assigned')
self.assertEqual(move_stock_postprod.state, 'waiting')
move_stock_preprod._action_cancel()
self.assertEqual(production_order.state, 'confirmed')
production_order.action_cancel()
self.assertTrue(move_stock_postprod.state, 'cancel')
def test_no_initial_demand(self):
""" Test MO/picking before manufacturing/picking after manufacturing
@ -294,7 +326,7 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
])
new_product = self.env['product.product'].create({
'name': 'New product',
'type': 'product',
'is_storable': True,
})
bom.consumption = 'flexible'
production_form = Form(self.env['mrp.production'])
@ -332,19 +364,17 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
one_unit_uom = self.env.ref('uom.product_uom_unit')
[two_units_uom, four_units_uom] = self.env['uom.uom'].create([{
'name': 'x%s' % i,
'category_id': self.ref('uom.product_uom_categ_unit'),
'uom_type': 'bigger',
'factor_inv': i,
'relative_factor': i,
'relative_uom_id': one_unit_uom.id,
} for i in [2, 4]])
finished_product = self.env['product.product'].create({
'name': 'Super Product',
'route_ids': [(4, self.ref('mrp.route_warehouse0_manufacture'))],
'type': 'product',
'is_storable': True,
})
secondary_product = self.env['product.product'].create({
'name': 'Secondary',
'type': 'product',
'is_storable': True,
})
component = self.env['product.product'].create({
'name': 'Component',
@ -375,15 +405,18 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
'product_max_qty': 2,
})
self.env['procurement.group'].run_scheduler()
self.env['stock.rule'].run_scheduler()
mo = self.env['mrp.production'].search([('product_id', '=', finished_product.id)])
pickings = mo.picking_ids
self.assertEqual(len(pickings), 2)
self.assertEqual(len(pickings), 1)
preprod_picking = pickings[0] if pickings[0].location_id == warehouse_stock_location else pickings[1]
self.assertEqual(preprod_picking.location_id, warehouse_stock_location)
self.assertEqual(preprod_picking.location_dest_id, pre_production_location)
mo.button_mark_done()
pickings = mo.picking_ids
self.assertEqual(len(pickings), 2)
postprod_picking = pickings - preprod_picking
self.assertEqual(postprod_picking.location_id, post_production_location)
self.assertEqual(postprod_picking.location_dest_id, warehouse_stock_location)
@ -393,23 +426,18 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
('location_id', '=', post_production_location.id),
('location_dest_id', '=', warehouse_stock_location.id),
])
self.assertEqual(byproduct_postprod_move.state, 'waiting')
self.assertEqual(byproduct_postprod_move.group_id.name, mo.name)
self.assertEqual(byproduct_postprod_move.state, 'assigned')
self.assertEqual(byproduct_postprod_move.reference_ids.name, mo.name)
def test_manufacturing_3_steps_trigger_reordering_rules(self):
with Form(self.warehouse) as warehouse:
warehouse.manufacture_steps = 'pbm_sam'
with Form(self.raw_product) as p:
p.route_ids.clear()
p.route_ids.add(self.warehouse.manufacture_pull_id.route_id)
# Create an additional BoM for component
product_form = Form(self.env['product.product'])
product_form.name = 'Wood'
product_form.detailed_type = 'product'
product_form.is_storable = True
product_form.uom_id = self.uom_unit
product_form.uom_po_id = self.uom_unit
self.wood_product = product_form.save()
# Create bom for manufactured product
@ -435,19 +463,19 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
rr_form = Form(self.env['stock.warehouse.orderpoint'])
rr_form.product_id = self.finished_product
rr_form.location_id = self.warehouse.lot_stock_id
rr_finish = rr_form.save()
rr_form.save()
rr_form = Form(self.env['stock.warehouse.orderpoint'])
rr_form.product_id = self.raw_product
rr_form.location_id = self.warehouse.lot_stock_id
rr_form.save()
rr_raw = rr_form.save()
self.env['procurement.group'].run_scheduler()
self.env['stock.rule'].run_scheduler()
pickings_component = self.env['stock.picking'].search(
[('product_id', '=', self.wood_product.id)])
self.assertTrue(pickings_component)
self.assertTrue(rr_finish.name in pickings_component.origin)
self.assertTrue(rr_raw.name in pickings_component.origin)
def test_2_steps_and_additional_moves(self):
""" Suppose a 2-steps configuration. If a user adds a product to an existing draft MO and then
@ -466,7 +494,6 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
'location_dest_id': component_move.location_dest_id.id,
'picking_type_id': component_move.picking_type_id.id,
'product_id': self.product_2.id,
'name': self.product_2.display_name,
'product_uom_qty': 1,
'product_uom': self.product_2.uom_id.id,
'warehouse_id': component_move.warehouse_id.id,
@ -478,114 +505,6 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
self.assertEqual(self.bom.bom_line_ids.product_id + self.product_2, mo.picking_ids.move_ids.product_id)
def test_manufacturing_complex_product_3_steps(self):
""" Test MO/picking after manufacturing a complex product which uses
manufactured components. Ensure that everything is created and picked
correctly.
"""
self.warehouse.mto_pull_id.route_id.active = True
# Creating complex product which trigger another manifacture
routes = self.warehouse.manufacture_pull_id.route_id + self.warehouse.mto_pull_id.route_id
self.complex_product = self.env['product.product'].create({
'name': 'Arrow',
'type': 'product',
'route_ids': [(6, 0, routes.ids)],
})
# Create raw product for manufactured product
self.raw_product_2 = self.env['product.product'].create({
'name': 'Raw Iron',
'type': 'product',
'uom_id': self.uom_unit.id,
'uom_po_id': self.uom_unit.id,
})
self.finished_product.route_ids = [(6, 0, routes.ids)]
# Create bom for manufactured product
bom_product_form = Form(self.env['mrp.bom'])
bom_product_form.product_id = self.complex_product
bom_product_form.product_tmpl_id = self.complex_product.product_tmpl_id
with bom_product_form.bom_line_ids.new() as line:
line.product_id = self.finished_product
line.product_qty = 1.0
with bom_product_form.bom_line_ids.new() as line:
line.product_id = self.raw_product_2
line.product_qty = 1.0
self.complex_bom = bom_product_form.save()
with Form(self.warehouse) as warehouse:
warehouse.manufacture_steps = 'pbm_sam'
production_form = Form(self.env['mrp.production'])
production_form.product_id = self.complex_product
production_form.picking_type_id = self.warehouse.manu_type_id
production = production_form.save()
production.action_confirm()
move_raw_ids = production.move_raw_ids
self.assertEqual(len(move_raw_ids), 2)
sfp_move_raw_id, raw_move_raw_id = move_raw_ids
self.assertEqual(sfp_move_raw_id.product_id, self.finished_product)
self.assertEqual(raw_move_raw_id.product_id, self.raw_product_2)
for move_raw_id in move_raw_ids:
self.assertEqual(move_raw_id.picking_type_id, self.warehouse.manu_type_id)
pbm_move = move_raw_id.move_orig_ids
self.assertEqual(len(pbm_move), 1)
self.assertEqual(pbm_move.location_id, self.warehouse.lot_stock_id)
self.assertEqual(pbm_move.location_dest_id, self.warehouse.pbm_loc_id)
self.assertEqual(pbm_move.picking_type_id, self.warehouse.pbm_type_id)
# Check move locations
move_finished_ids = production.move_finished_ids
self.assertEqual(len(move_finished_ids), 1)
self.assertEqual(move_finished_ids.product_id, self.complex_product)
self.assertEqual(move_finished_ids.picking_type_id, self.warehouse.manu_type_id)
sam_move = move_finished_ids.move_dest_ids
self.assertEqual(len(sam_move), 1)
self.assertEqual(sam_move.location_id, self.warehouse.sam_loc_id)
self.assertEqual(sam_move.location_dest_id, self.warehouse.lot_stock_id)
self.assertEqual(sam_move.picking_type_id, self.warehouse.sam_type_id)
self.assertFalse(sam_move.move_dest_ids)
subproduction = self.env['mrp.production'].browse(production.id+1)
sfp_pickings = subproduction.picking_ids.sorted('id')
# SFP Production: 2 pickings, 1 group
self.assertEqual(len(sfp_pickings), 2)
self.assertEqual(sfp_pickings.mapped('group_id'), subproduction.procurement_group_id)
# Move Raw Stick - Stock -> Preprocessing
picking = sfp_pickings[0]
self.assertEqual(len(picking.move_ids), 1)
picking.move_ids[0].product_id = self.raw_product
# Move SFP - PostProcessing -> Stock
picking = sfp_pickings[1]
self.assertEqual(len(picking.move_ids), 1)
picking.move_ids[0].product_id = self.finished_product
# Main production 2 pickings, 1 group
pickings = production.picking_ids.sorted('id')
self.assertEqual(len(pickings), 2)
self.assertEqual(pickings.mapped('group_id'), production.procurement_group_id)
# Move 2 components Stock -> Preprocessing
picking = pickings[0]
self.assertEqual(len(picking.move_ids), 2)
picking.move_ids[0].product_id = self.finished_product
picking.move_ids[1].product_id = self.raw_product_2
# Move FP PostProcessing -> Stock
picking = pickings[1]
self.assertEqual(len(picking.move_ids), 1)
picking.product_id = self.complex_product
def test_child_parent_relationship_on_backorder_creation(self):
""" Test Child Mo and Source Mo in 2/3-step production for reorder
rules in backorder using order points with the help of run scheduler """
@ -599,7 +518,7 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
rr_form.product_max_qty = 40
rr_form.save()
self.env['procurement.group'].run_scheduler()
self.env['stock.rule'].run_scheduler()
mo = self.env['mrp.production'].search([('product_id', '=', self.finished_product.id)])
mo_form = Form(mo)
@ -667,7 +586,7 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
warehouse.manufacture_steps = 'pbm_sam'
finished_product = self.env['product.product'].create({
'name': 'Product',
'type': 'product',
'is_storable': True,
'route_ids': manufacturing_route,
})
self.env['mrp.bom'].create({
@ -690,8 +609,286 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon):
'route_id': manufacturing_route.id,
'bom_id': bom_2.id,
})
self.env['procurement.group'].run_scheduler()
self.env['stock.rule'].run_scheduler()
mo = self.env['mrp.production'].search([('product_id', '=', self.finished_product.id)])
self.assertEqual(len(mo), 1)
self.assertEqual(mo.product_qty, 1.0)
self.assertEqual(mo.bom_id, bom_2)
# def test_manufacturing_bom_with_repetitions(self):
# """
# Checks that manufacturing orders created to manufacture the components of a BOM
# are set with the correct quantities when products appear with repetitions.
# - Create 5 products: product 1,2,3,4 (P1,P2,P3 and P4) and a final product (FP)
# - Set routes to manifacture on each product
# - For P1, P2, P3, P4 add a 0:0 reordering rule.
# - Add a BOM for P2 with 1 unit of P1 as components
# - Add a BOM for P3 with 1 unit of P2 as components
# - Add a BOM for P4 with 1 unit of P3 as components
# - Add a BOM for FP with 3 unit of P4 and 2 units of P3 as components
# """
# manufacturing_route = self.env['stock.rule'].search([
# ('action', '=', 'manufacture')]).route_id
# products = self.env['product.product'].create([
# {
# 'name': 'FP',
# 'is_storable': True,
# 'route_ids': manufacturing_route,
# },
# {
# 'name': 'P1',
# 'is_storable': True,
# 'route_ids': manufacturing_route,
# },
# {
# 'name': 'P2',
# 'is_storable': True,
# 'route_ids': manufacturing_route,
# },
# {
# 'name': 'P3',
# 'is_storable': True,
# 'route_ids': manufacturing_route,
# },
# {
# 'name': 'P4',
# 'is_storable': True,
# 'route_ids': manufacturing_route,
# },
#
# ])
# self.env['stock.warehouse.orderpoint'].create([
# {
# 'name': 'My orderpoint',
# 'product_id': i,
# 'product_min_qty': 0,
# 'product_max_qty': 0,
# } for i in products.ids[1:]
# ])
# self.env['mrp.bom'].create([
# {
# 'product_tmpl_id': products[2].product_tmpl_id.id,
# 'product_qty': 1,
# 'product_uom_id': products[2].uom_id.id,
# 'type': 'normal',
# 'bom_line_ids': [
# Command.create({
# 'product_id': products[1].id,
# 'product_qty': 1,
# })
# ]},
# {
# 'product_tmpl_id': products[3].product_tmpl_id.id,
# 'product_qty': 1,
# 'product_uom_id': products[3].uom_id.id,
# 'type': 'normal',
# 'bom_line_ids': [
# Command.create({
# 'product_id': products[2].id,
# 'product_qty': 1,
# })
# ]},
# {
# 'product_tmpl_id': products[4].product_tmpl_id.id,
# 'product_qty': 1,
# 'product_uom_id': products[4].uom_id.id,
# 'type': 'normal',
# 'bom_line_ids': [
# Command.create({
# 'product_id': products[3].id,
# 'product_qty': 1,
# })
# ]},
# {
# 'product_tmpl_id': products[0].product_tmpl_id.id,
# 'product_qty': 1,
# 'product_uom_id': products[0].uom_id.id,
# 'type': 'normal',
# 'bom_line_ids': [
# Command.create({
# 'product_id': products[4].id,
# 'product_qty': 3,
# }),
# Command.create({
# 'product_id': products[2].id,
# 'product_qty': 2,
# }),
# ]},
# ])
# mo = self.env['mrp.production'].create({
# 'product_id': products[0].id,
# 'product_uom_qty': 1,
# })
# mo.action_confirm()
# mo_P1 = self.env['mrp.production'].search([('product_id', '=', products[1].id)])
# mo_P2 = self.env['mrp.production'].search([('product_id', '=', products[2].id)])
# self.assertEqual(mo_P1.product_uom_qty, 5.0)
# self.assertEqual(mo_P2.product_uom_qty, 5.0)
#
def test_update_component_qty(self):
self.warehouse.manufacture_steps = "pbm"
component = self.bom.bom_line_ids.product_id
mo = self.env['mrp.production'].create({
'product_id': self.bom.product_id.id,
'bom_id': self.bom.id,
'product_qty': 1,
'location_src_id': self.warehouse.pbm_loc_id.id,
})
mo.action_confirm()
self.assertEqual(mo.move_raw_ids.product_uom_qty, 2.0)
self.assertEqual(mo.picking_ids.move_ids.product_uom_qty, 2.0)
# we require a more components to complete the MO
mo_form = Form(mo)
with mo_form.move_raw_ids.new() as raw_move:
raw_move.product_id = component
raw_move.product_uom_qty = 1.0
mo = mo_form.save()
# check that the related moves qty is correctly updated
self.assertEqual(mo.move_raw_ids.product_uom_qty, 3.0)
self.assertEqual(mo.picking_ids.move_ids.product_uom_qty, 3.0)
def test_component_and_byproduct_on_transfers(self):
"""
Checks if transfers is updated when we adding a new byproduct/component
after confirm the MO
"""
self.env.user.group_ids += self.env.ref('mrp.group_mrp_byproducts')
demo = self.env['product.product'].create({
'name': 'DEMO',
'is_storable': True,
})
comp1 = self.env['product.product'].create({
'name': 'COMP1'
})
comp2 = self.env['product.product'].create({
'name': 'COMP2'
})
bprod1 = self.env['product.product'].create({
'name': 'BPROD1'
})
bprod2 = self.env['product.product'].create({
'name': 'BPROD2'
})
warehouse = self.warehouse
warehouse.manufacture_steps = 'pbm_sam'
warehouse_stock_location = warehouse.lot_stock_id
self.env['mrp.bom'].create({
'product_tmpl_id': demo.product_tmpl_id.id,
'product_qty': 1,
'bom_line_ids': [(0, 0, {
'product_id': comp1.id,
'product_qty': 1,
})],
'byproduct_ids': [(0, 0, {
'product_id': bprod1.id,
'product_qty': 1,
})],
})
self.env['stock.warehouse.orderpoint'].create({
'warehouse_id': warehouse.id,
'location_id': warehouse_stock_location.id,
'product_id': demo.id,
'product_min_qty': 2,
'product_max_qty': 2,
})
self.env['stock.rule'].run_scheduler()
mo = self.env['mrp.production'].search([('product_id', '=', demo.id)])
mo.action_confirm()
mo_form = Form(mo)
with mo_form.move_raw_ids.new() as raw_move:
raw_move.product_id = comp2
raw_move.product_uom_qty = 1.0
with mo_form.move_byproduct_ids.new() as byprod_move:
byprod_move.product_id = bprod2
byprod_move.quantity = 1.0
mo = mo_form.save()
mo.with_context({'skip_consumption': True}).button_mark_done()
self.assertEqual(len(mo.picking_ids), 2, "Should have 2 pickings: Components + (Final product and byproducts)")
for picking in mo.picking_ids:
if demo in [m.product_id for m in picking.move_ids]:
self.assertEqual(len(picking.move_ids), 3, "Should have 3 moves for: Demo, Bprod1 and Bprod2")
self.assertEqual([move.product_id for move in picking.move_ids.sorted(lambda m: bool(m.product_id))], [demo, bprod1, bprod2])
else:
self.assertEqual(len(picking.move_ids), 2, "Should have 2 moves for: Comp1 and Comp2")
self.assertEqual([move.product_id for move in picking.move_ids.sorted(lambda m: bool(m.product_id))], [comp1, comp2])
def test_pick_components_uses_shipping_policy_from_picking_type(self):
self.warehouse.manufacture_steps = "pbm"
pick_components_type = self.warehouse.pbm_type_id
for move_type in ["direct", "one"]:
pick_components_type.move_type = move_type
mo = self.env["mrp.production"].create({
"bom_id": self.bom.id,
"location_src_id": self.warehouse.pbm_loc_id.id,
})
mo.action_confirm()
self.assertEqual(mo.picking_ids[0].picking_type_id, pick_components_type)
self.assertEqual(mo.picking_ids[0].move_type, move_type)
def test_update_mo_from_bom_forecast(self):
self.warehouse_1.manufacture_steps = 'pbm_sam'
self.env['stock.quant']._update_available_quantity(self.product_2, self.warehouse_1.lot_stock_id, 10)
self.env['stock.quant']._update_available_quantity(self.product_3, self.warehouse_1.lot_stock_id, 20)
mo = self.env['mrp.production'].create({
'bom_id': self.bom_1.id,
'picking_type_id': self.warehouse_1.manu_type_id.id,
})
mo.action_confirm()
self.assertEqual(self.product_1.virtual_available, -4)
self.assertEqual(self.product_2.virtual_available, 8)
rr = self.env['stock.warehouse.orderpoint'].create({
'name': 'John Cutter RR',
'product_id': self.product_1.id,
'warehouse_id': mo.warehouse_id.id,
})
self.assertEqual(rr.qty_forecast, -4)
# Update the BoM
self.bom_1.bom_line_ids[1].unlink()
self.bom_1.bom_line_ids[0].product_qty = 3
self.env['mrp.bom.line'].create({
'product_id': self.product_3.id,
'product_qty': 5,
'bom_id': self.bom_1.id,
})
mo.action_update_bom()
self.assertEqual(rr.qty_forecast, 0)
self.assertEqual(self.product_1.virtual_available, 0)
self.assertEqual(self.product_2.virtual_available, 7)
self.assertEqual(self.product_3.virtual_available, 15)
pre_prod_pick = mo.picking_ids.filtered(lambda p: p.picking_type_id == mo.warehouse_id.pbm_type_id)
self.assertRecordValues(pre_prod_pick.move_ids, [
{'product_id': self.product_2.id, 'product_uom_qty': 3, 'product_qty_available': 10},
{'product_id': self.product_1.id, 'product_uom_qty': 0, 'product_qty_available': 0},
{'product_id': self.product_3.id, 'product_uom_qty': 5, 'product_qty_available': 20},
])
def test_3_steps_manufacturing_forecast(self):
"""Check that a confirmed MO influence the forecast of the warehouse stock"""
self.warehouse_1.manufacture_steps = 'pbm_sam'
lovely_product = self.bom_1.product_id.copy({'uom_id': self.uom_unit.id})
self.bom_1.product_id = lovely_product
self.assertEqual(lovely_product.with_context(location_id=self.warehouse_1.lot_stock_id.id).virtual_available, 0.0)
mo = self.env['mrp.production'].create({
'bom_id': self.bom_1.id,
'picking_type_id': self.warehouse_1.manu_type_id.id,
'product_qty': 3.0,
})
mo.action_confirm()
self.assertEqual(mo.state, 'confirmed')
self.assertEqual(lovely_product.with_context(location_id=self.warehouse_1.lot_stock_id.id).virtual_available, 3.0)
def test_manufacture_to_resupply_unchecks_and_unlinks_warehouse(self):
"""Unchecking Manufacture to Resupply should keep manufacture_to_resupply disabled."""
manufacture_route = self.warehouse.manufacture_pull_id.route_id
self.warehouse.manufacture_to_resupply = False
self.assertFalse(self.warehouse.manufacture_to_resupply)
self.assertNotIn(self.warehouse, manufacture_route.warehouse_ids)