From 99c3e750c3eb63e8fd7deb48617cc4456e3cce49 Mon Sep 17 00:00:00 2001 From: "Adrien Widart (awt)" Date: Fri, 28 Oct 2022 09:06:59 +0000 Subject: [PATCH] [FIX] mrp: check SN uniqueness on WO When marking a WO as done, if the serial number defined is related to an unbuilt product, an error will be raised and the user will not be able to mark the WO as done To reproduce the issue: 1. Create a BoM for product P with one operation - P is tracked by SN 2. Produce one P with serial S 3. Unbuild it 4. Create and confirm a second MO with 1 x P 5. Start the WO 6. On tablet view, set the finished lot to S 7. Mark the WO as done Error: a UserError is raised because "This serial number [...] has already been produced". However, this serial number has been unbuilt so the worker should be able to use it again When marking the WO as done, we check the uniqueness of the defined serial number. But: - The check is not accurate enough, hence the above error - The lot of the WO is a computed/inverse field based on lot of the MO - Once the WO closed, we can still change the lot of the MO - When marking the MO as done, a better method checks the SN uniqueness (does not fail in the above case) Therefore, the checking on WO side is useless. We should let the MO side handle this. Moreover, let's say that there is already one P in stock with serial S2. On tablet view, if the worker set the lot to S2, there should be a warning so he can be aware of the situation. This is already the case on MO side: https://github.com/odoo/odoo/blob/45e37b2ad7bdcfd9f9f7e1dabbd0a99c9a0b5cdc/addons/mrp/models/mrp_production.py#L694-L705 (This commit is linked to a similar commit OE side, same opw) OPW-3002424 closes odoo/odoo#106152 X-original-commit: 60a4c37c781ceb20123cb99603ddd2890b1c806c Related: odoo/enterprise#34183 Signed-off-by: Tiffany Chang Signed-off-by: Adrien Widart --- addons/mrp/models/mrp_production.py | 14 ++++++++++---- addons/mrp/models/mrp_workorder.py | 18 ++++++------------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py index 34d64f50fb0..e424be4fd14 100644 --- a/addons/mrp/models/mrp_production.py +++ b/addons/mrp/models/mrp_production.py @@ -736,12 +736,18 @@ class MrpProduction(models.Model): @api.onchange('lot_producing_id') def _onchange_lot_producing(self): - if self.product_id.tracking == 'serial' and self.lot_producing_id: - message, dummy = self.env['stock.quant'].sudo()._check_serial_number(self.product_id, - self.lot_producing_id, - self.company_id) + res = self._can_produce_serial_number() + if res is not True: + return res + + def _can_produce_serial_number(self, sn=None): + self.ensure_one() + sn = sn or self.lot_producing_id + if self.product_id.tracking == 'serial' and sn: + message, dummy = self.env['stock.quant'].sudo()._check_serial_number(self.product_id, sn, self.company_id) if message: return {'warning': {'title': _('Warning'), 'message': message}} + return True @api.onchange('product_id', 'move_raw_ids') def _onchange_product_id(self): diff --git a/addons/mrp/models/mrp_workorder.py b/addons/mrp/models/mrp_workorder.py index 571de8ea775..a3aabdbf008 100644 --- a/addons/mrp/models/mrp_workorder.py +++ b/addons/mrp/models/mrp_workorder.py @@ -437,6 +437,12 @@ class MrpWorkorder(models.Model): ) return interval['hours'] * 60 + @api.onchange('finished_lot_id') + def _onchange_finished_lot_id(self): + res = self.production_id._can_produce_serial_number(sn=self.finished_lot_id) + if res is not True: + return res + def write(self, values): if 'production_id' in values and any(values['production_id'] != w.production_id.id for w in self): raise UserError(_('You cannot link this work order to another manufacturing order.')) @@ -843,18 +849,6 @@ class MrpWorkorder(models.Model): float_round(self.qty_producing, precision_rounding=rounding) ) - def _check_sn_uniqueness(self): - """ Alert the user if the serial number as already been produced """ - if self.product_tracking == 'serial' and self.finished_lot_id: - sml = self.env['stock.move.line'].search_count([ - ('lot_id', '=', self.finished_lot_id.id), - ('location_id.usage', '=', 'production'), - ('qty_done', '=', 1), - ('state', '=', 'done') - ]) - if sml: - raise UserError(_('This serial number for product %s has already been produced', self.product_id.name)) - def _should_start_timer(self): return True