From 89f5f504be994a8a0de1d33db6f3445c9a149915 Mon Sep 17 00:00:00 2001 From: Adrien Widart Date: Wed, 14 Jul 2021 08:12:40 +0000 Subject: [PATCH] [FIX] mrp: create SM for by-products when RR triggered When combining a reordering rule, the 3-steps manufacture and by-products option, the picking from the post-production to the stock will not contain the residual products produced by the MO (by-products) To reproduce the error: 1. In Settings, enable: - By-Products - Multi-Step Routes 2. Inventory > Configuration > Warehouse Management > Warehouses, edit company's warehouse: - Manufacture: 3 steps 3. Create 3 products P_compo, P_finished, P_secondary - P_compo is consumable - P_finished and P_secondary are storable - Routes of P_finished: Manufacture 4. Create a reordering rule for P_finished: - Min = Max = 1 5. Create a BoM: - Product: P_finished - Type: Manufacture - Components: 1 x P_compo - By-products: 1 x P_secondary 6. Inventory > Operations > Run Scheduler 7. Open the generated MO 8. Check Availability, Produce, Mark as Done - Note that in the "Produce" wizard, we mention that one P_secondary is also produced - Also note that in "Finished Products" tab, there are 1 x P_finished and 1 x P_secondary 9. Open the Transfers Error: The picking Post-Production -> Stock does not exist When creating the byproducts move https://github.com/odoo/odoo/blob/ad62f877c174d56b90ec516cf24494d751383db9/addons/mrp/models/mrp_production.py#L587 the field `move_dest_ids` is present (is the move created after evaluating the RR) https://github.com/odoo/odoo/blob/ad62f877c174d56b90ec516cf24494d751383db9/addons/mrp/models/mrp_production.py#L580 so it is used, but this will cause the `_push_apply` to skip the evaluation of the move https://github.com/odoo/odoo/blob/f0eaa756c4947e2a595359959b34b14bfda81a07/addons/stock/models/stock_move.py#L678-L679 and `_assign_picking` will not run, as it normally do when creating the manufacture Thanks to this change, the picking Post-Production -> Stock will exist and contain the residual products OPW-2581762 closes odoo/odoo#75068 X-original-commit: 098af2fa85d2aebfc71b7e2342a1bbf05100e10d Signed-off-by: William Henrotin --- addons/mrp/models/mrp_production.py | 2 +- .../test_warehouse_multistep_manufacturing.py | 81 +++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py index 158bff19ee2..160fc8ae7f0 100644 --- a/addons/mrp/models/mrp_production.py +++ b/addons/mrp/models/mrp_production.py @@ -856,7 +856,7 @@ class MrpProduction(models.Model): 'origin': self.name, 'group_id': self.procurement_group_id.id, 'propagate_cancel': self.propagate_cancel, - 'move_dest_ids': [(4, x.id) for x in move_dest_ids], + 'move_dest_ids': [(4, x.id) for x in self.move_dest_ids if not byproduct_id], } def _get_moves_finished_values(self): diff --git a/addons/mrp/tests/test_warehouse_multistep_manufacturing.py b/addons/mrp/tests/test_warehouse_multistep_manufacturing.py index 843dbd9a05b..a9c0c867f12 100644 --- a/addons/mrp/tests/test_warehouse_multistep_manufacturing.py +++ b/addons/mrp/tests/test_warehouse_multistep_manufacturing.py @@ -308,3 +308,84 @@ class TestMultistepManufacturingWarehouse(TestMrpCommon): pbm_move = move_raw_ids.move_orig_ids self.assertEqual(len(pbm_move), 2) self.assertTrue(new_product in pbm_move.product_id) + + def test_3_steps_and_byproduct(self): + """ Suppose a warehouse with Manufacture option set to '3 setps' and a product P01 with a reordering rule. + Suppose P01 has a BoM and this BoM mentions that when some P01 are produced, some P02 are produced too. + This test ensures that when a MO is generated thanks to the reordering rule, 2 pickings are also + generated: + - One to bring the components + - Another to return the P01 and P02 produced + """ + warehouse = self.warehouse + warehouse.manufacture_steps = 'pbm_sam' + warehouse_stock_location = warehouse.lot_stock_id + pre_production_location = warehouse.pbm_loc_id + post_production_location = warehouse.sam_loc_id + + 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, + } 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', + }) + secondary_product = self.env['product.product'].create({ + 'name': 'Secondary', + 'type': 'product', + }) + component = self.env['product.product'].create({ + 'name': 'Component', + 'type': 'consu', + }) + + self.env['mrp.bom'].create({ + 'product_tmpl_id': finished_product.product_tmpl_id.id, + 'product_qty': 1, + 'product_uom_id': two_units_uom.id, + 'bom_line_ids': [(0, 0, { + 'product_id': component.id, + 'product_qty': 1, + 'product_uom_id': one_unit_uom.id, + })], + 'byproduct_ids': [(0, 0, { + 'product_id': secondary_product.id, + 'product_qty': 1, + 'product_uom_id': four_units_uom.id, + })], + }) + + self.env['stock.warehouse.orderpoint'].create({ + 'warehouse_id': warehouse.id, + 'location_id': warehouse_stock_location.id, + 'product_id': finished_product.id, + 'product_min_qty': 2, + 'product_max_qty': 2, + }) + + self.env['procurement.group'].run_scheduler() + mo = self.env['mrp.production'].search([('product_id', '=', finished_product.id)]) + pickings = mo.picking_ids + self.assertEqual(len(pickings), 2) + + 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) + + postprod_picking = pickings - preprod_picking + self.assertEqual(postprod_picking.location_id, post_production_location) + self.assertEqual(postprod_picking.location_dest_id, warehouse_stock_location) + + byproduct_postprod_move = self.env['stock.move'].search([ + ('product_id', '=', secondary_product.id), + ('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)