From a4c00c071f5a2ba95dd778184f99aaef81633767 Mon Sep 17 00:00:00 2001 From: "Touati Djamel (otd)" Date: Thu, 30 Jun 2022 15:24:58 +0000 Subject: [PATCH] [FIX] mrp: allow using an unbuilt serial number in manufacturing order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Steps to reproduce the bug: - Create a storable product “P1” - Tracking: by serial number - BOM: - Component: C1 - Create a storable product “P2” - BOM: - Component: P1 - Create a MO to produce one unit of P1: - serial number: SN1 - Confirm and mark as done - Unbuild the manufactured product - Manufacture the same product using the same serial number again - Create a new MO to produce one unit of “P2”: - Component P1 → select SN1 - Try to confirm and validate the MO Problem: Get User Error: The serial number “SN1” used for component “P1” has already been consumed We do a search in the `stock.move.line` to find if the SN has already been used in a previous MO, but there is no specific condition to get only those used in an MO so the unbuild order is in the same condition and therefore the SN is considered as it has already been used opw-2883450 closes odoo/odoo#95935 X-original-commit: 5ac7f4d6fa5551ba7c6da49a52edf0a7df2d0745 Signed-off-by: William Henrotin (whe) Signed-off-by: Djamel Touati (otd) --- addons/mrp/models/mrp_production.py | 1 + addons/mrp/tests/test_unbuild.py | 80 +++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py index fed6b9dba52..e604d1e176d 100644 --- a/addons/mrp/models/mrp_production.py +++ b/addons/mrp/models/mrp_production.py @@ -2108,6 +2108,7 @@ class MrpProduction(models.Model): ('qty_done', '=', 1), ('state', '=', 'done'), ('location_dest_id.usage', '=', 'production'), + ('production_id', '!=', False), ]) if duplicates: # Maybe some move lines have been compensated by unbuild diff --git a/addons/mrp/tests/test_unbuild.py b/addons/mrp/tests/test_unbuild.py index 2061bedd673..cc30780ac35 100644 --- a/addons/mrp/tests/test_unbuild.py +++ b/addons/mrp/tests/test_unbuild.py @@ -752,3 +752,83 @@ class TestUnbuild(TestMrpCommon): warehouse = self.env.ref('stock.warehouse0') self.assertEqual(order.location_id, warehouse.lot_stock_id) self.assertEqual(order.location_dest_id, warehouse.lot_stock_id) + + def test_use_unbuilt_sn_in_mo(self): + """ + use an unbuilt serial number in manufacturing order: + produce a tracked product, unbuild it and then use it as a component with the same SN in a mo. + """ + product_1 = self.env['product.product'].create({ + 'name': 'Product tracked by sn', + 'type': 'product', + 'tracking': 'serial', + }) + product_1_sn = self.env['stock.lot'].create({ + 'name': 'sn1', + 'product_id': product_1.id, + 'company_id': self.env.company.id + }) + component = self.env['product.product'].create({ + 'name': 'Product component', + 'type': 'product', + }) + bom_1 = self.env['mrp.bom'].create({ + 'product_id': product_1.id, + 'product_tmpl_id': product_1.product_tmpl_id.id, + 'product_uom_id': self.env.ref('uom.product_uom_unit').id, + 'product_qty': 1.0, + 'type': 'normal', + 'bom_line_ids': [ + (0, 0, {'product_id': component.id, 'product_qty': 1}), + ], + }) + product_2 = self.env['product.product'].create({ + 'name': 'finished Product', + 'type': 'product', + }) + self.env['mrp.bom'].create({ + 'product_id': product_2.id, + 'product_tmpl_id': product_2.product_tmpl_id.id, + 'product_uom_id': self.env.ref('uom.product_uom_unit').id, + 'product_qty': 1.0, + 'type': 'normal', + 'bom_line_ids': [ + (0, 0, {'product_id': product_1.id, 'product_qty': 1}), + ], + }) + # mo1 + mo_form = Form(self.env['mrp.production']) + mo_form.product_id = product_1 + mo_form.bom_id = bom_1 + mo_form.product_qty = 1.0 + mo = mo_form.save() + mo.action_confirm() + + mo_form = Form(mo) + mo_form.qty_producing = 1.0 + mo_form.lot_producing_id = product_1_sn + mo = mo_form.save() + mo.button_mark_done() + self.assertEqual(mo.state, 'done', "Production order should be in done state.") + + #unbuild order + unbuild_form = Form(self.env['mrp.unbuild']) + unbuild_form.mo_id = mo + unbuild_form.lot_id = product_1_sn + unbuild_form.save().action_unbuild() + + #mo2 + mo_form = Form(self.env['mrp.production']) + mo_form.product_id = product_2 + mo2 = mo_form.save() + mo2.action_confirm() + details_operation_form = Form(mo2.move_raw_ids[0], view=self.env.ref('stock.view_stock_move_operations')) + with details_operation_form.move_line_ids.new() as ml: + ml.lot_id = product_1_sn + ml.qty_done = 1 + details_operation_form.save() + mo_form = Form(mo2) + mo_form.qty_producing = 1 + mo2 = mo_form.save() + mo2.button_mark_done() + self.assertEqual(mo2.state, 'done', "Production order should be in done state.")