diff --git a/addons/stock/models/product.py b/addons/stock/models/product.py index df844cb17c6..77eedc0d1a7 100644 --- a/addons/stock/models/product.py +++ b/addons/stock/models/product.py @@ -500,6 +500,13 @@ class ProductTemplate(models.Model): done_moves = self.env['stock.move'].search([('product_id', 'in', updated.mapped('product_variant_ids').ids)], limit=1) if done_moves: raise UserError(_("You can not change the unit of measure of a product that has already been used in a done stock move. If you need to change the unit of measure, you may deactivate this product.")) + if 'type' in vals: + existing_move_lines = self.env['stock.move.line'].search([ + ('product_id', 'in', self.mapped('product_variant_ids').ids), + ('state', 'in', ['partially_available', 'assigned']), + ]) + if existing_move_lines: + raise UserError(_("You can not change the type of a product that is currently reserved on a stock move. If you need to change the type, you should first unreserve the stock move.")) return super(ProductTemplate, self).write(vals) def action_view_routes(self): diff --git a/addons/stock/tests/test_move.py b/addons/stock/tests/test_move.py index aedffbdced3..a83a6c87c41 100644 --- a/addons/stock/tests/test_move.py +++ b/addons/stock/tests/test_move.py @@ -2935,3 +2935,43 @@ class StockMove(TransactionCase): self.assertEqual(move1.state, 'assigned') self.assertEqual(move1.product_uom_qty, 5) self.assertEqual(len(move1.move_line_ids), 1) + + def test_change_product_type(self): + """ Changing type of an existing product will raise a user error if some move + are reserved. + """ + self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 10) + move1 = self.env['stock.move'].create({ + 'name': 'test_customer', + 'location_id': self.stock_location.id, + 'location_dest_id': self.customer_location.id, + 'product_id': self.product1.id, + 'product_uom': self.uom_unit.id, + 'product_uom_qty': 5, + 'picking_type_id': self.env.ref('stock.picking_type_out').id, + }) + move1._action_confirm() + move1._action_assign() + + with self.assertRaises(UserError): + self.product1.type = 'consu' + move1._action_cancel() + self.product1.type = 'consu' + + move2 = self.env['stock.move'].create({ + 'name': 'test_customer', + 'location_id': self.stock_location.id, + 'location_dest_id': self.customer_location.id, + 'product_id': self.product1.id, + 'product_uom': self.uom_unit.id, + 'product_uom_qty': 5, + 'picking_type_id': self.env.ref('stock.picking_type_out').id, + }) + + move2._action_confirm() + move2._action_assign() + + with self.assertRaises(UserError): + self.product1.type = 'product' + move2._action_cancel() + self.product1.type = 'product'