From 7466779f2badafe2a71016c73e01894cc43f631d Mon Sep 17 00:00:00 2001 From: "Guillaume (guva)" Date: Tue, 29 Jun 2021 09:44:55 +0000 Subject: [PATCH] [FIX] mrp: issue with products with variants Step to follow - Create a product with 2 variants and set route to Manufacture - Create a BOM for the product - Create an MO for one of the variants - Save (in Draft State) - Edit - Change to the other variant - Confirm - Finish the MO Order - Look at product moves on MO Cause of the issue In MrpProduction._onchange_move_finished method, self.move_finished_ids was not empty before being assign. Solution Removed the records from self.move_finished_ids before assign another one to it. opw-2572644 closes odoo/odoo#73563 X-original-commit: 5e34a02c3d897d888bf52b1977c25047326b76a8 Signed-off-by: William Henrotin Signed-off-by: guva-odoo --- addons/mrp/models/mrp_production.py | 5 +- addons/mrp/tests/test_order.py | 80 +++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 3 deletions(-) diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py index f6722e849b1..defc194a6cf 100644 --- a/addons/mrp/models/mrp_production.py +++ b/addons/mrp/models/mrp_production.py @@ -615,9 +615,7 @@ class MrpProduction(models.Model): @api.onchange('bom_id', 'product_id', 'product_qty', 'product_uom_id') def _onchange_move_finished(self): if self.product_id and self.product_qty > 0: - # keep manual entries - list_move_finished = [(4, move.id) for move in self.move_finished_ids.filtered( - lambda m: not m.byproduct_id and m.product_id != self.product_id)] + list_move_finished = [] moves_finished_values = self._get_moves_finished_values() moves_byproduct_dict = {move.byproduct_id.id: move for move in self.move_finished_ids.filtered(lambda m: m.byproduct_id)} move_finished = self.move_finished_ids.filtered(lambda m: m.product_id == self.product_id) @@ -630,6 +628,7 @@ class MrpProduction(models.Model): else: # add new entries list_move_finished += [(0, 0, move_finished_values)] + self.move_finished_ids = [(5, 0, 0)] self.move_finished_ids = list_move_finished else: self.move_finished_ids = [(2, move.id) for move in self.move_finished_ids.filtered(lambda m: m.bom_line_id)] diff --git a/addons/mrp/tests/test_order.py b/addons/mrp/tests/test_order.py index b57f2a79a6e..c8af55626e3 100644 --- a/addons/mrp/tests/test_order.py +++ b/addons/mrp/tests/test_order.py @@ -1912,3 +1912,83 @@ class TestMrpOrder(TestMrpCommon): wizard = Form(self.env[res_dict['res_model']].with_context(res_dict['context'])).save() wizard.process() self.assertEqual(list(mo.workorder_ids.mapped("state")), ["done"]) + + def test_products_with_variants(self): + """Check for product with different variants with same bom""" + + product = self.env['product.template'].create({ + "attribute_line_ids": [ + [0, 0, {"attribute_id": 2, "value_ids": [[6, 0, [3, 4]]]}] + ], + "name": "Product with variants", + }) + + variant_1 = product.product_variant_ids[0] + variant_2 = product.product_variant_ids[1] + + component = self.env['product.template'].create({ + "name": "Component", + }) + + self.env['mrp.bom'].create({ + 'product_id': False, + 'product_tmpl_id': product.id, + 'bom_line_ids': [ + (0, 0, {'product_id': component.product_variant_id.id, 'product_qty': 1}) + ] + }) + + # First behavior to check, is changing the product (same product but another variant) after saving the MO a first time. + + mo_form_1 = Form(self.env['mrp.production']) + mo_form_1.product_id = variant_1 + mo_1 = mo_form_1.save() + mo_form_1 = Form(self.env['mrp.production'].browse(mo_1.id)) + mo_form_1.product_id = variant_2 + mo_1 = mo_form_1.save() + mo_1.action_confirm() + mo_1.action_assign() + mo_form_1 = Form(self.env['mrp.production'].browse(mo_1.id)) + mo_form_1.qty_producing = 1 + mo_1 = mo_form_1.save() + mo_1.button_mark_done() + + move_lines_1 = self.env['stock.move.line'].search([("reference", "=", mo_1.name)]) + + # Second behavior is changing the product before saving the MO + + mo_form_2 = Form(self.env['mrp.production']) + mo_form_2.product_id = variant_1 + mo_form_2.product_id = variant_2 + mo_2 = mo_form_2.save() + mo_2.action_confirm() + mo_2.action_assign() + mo_form_2 = Form(self.env['mrp.production'].browse(mo_2.id)) + mo_form_2.qty_producing = 1 + mo_2 = mo_form_2.save() + mo_2.button_mark_done() + + move_lines_2 = self.env['stock.move.line'].search([("reference", "=", mo_2.name)]) + + # Third behavior is changing the product before saving the MO, then another time after + + mo_form_3 = Form(self.env['mrp.production']) + mo_form_3.product_id = variant_1 + mo_form_3.product_id = variant_2 + mo_3 = mo_form_3.save() + mo_form_3 = Form(self.env['mrp.production'].browse(mo_3.id)) + mo_form_3.product_id = variant_1 + mo_3 = mo_form_3.save() + mo_3.action_confirm() + mo_3.action_assign() + mo_form_3 = Form(self.env['mrp.production'].browse(mo_3.id)) + mo_form_3.qty_producing = 1 + mo_3 = mo_form_3.save() + mo_3.button_mark_done() + + move_lines_3 = self.env['stock.move.line'].search([("reference", "=", mo_3.name)]) + + # There always should be only two move lines, one for the component, another for the product + self.assertEqual(len(move_lines_1), 2) + self.assertEqual(len(move_lines_2), 2) + self.assertEqual(len(move_lines_3), 2)