From d894472b18ab95cdb9e114b394f3e51f971bda64 Mon Sep 17 00:00:00 2001
From: Arnold Moyaux <arm@odoo.com>
Date: Mon, 22 May 2023 11:35:53 +0000
Subject: [PATCH] [FIX] stock: performance with 2000 serial numbers

It takes 70s to generate a receipt with 2000 serial numbers.

It happens because during the first part of the loop
(model `stock.move.line` in the `create` method).
It will update the initial demand of the move based on the new
stock.move.line and their qty_done.
Writing the initial demand of the `stock.move` will try to reassign
it (useless in our case) and rewrite the same value on its state's field.
The consequence is the invalidatation of the field on
the `stock.move.line` because it's a related to the `stock.move`.
In the second part of the loop, it check the sml state. Since it
was invalidate upper, it recompute it. That prevent a correct prefetch
and cause a performance issue.

We fix it by writing only once the information by move. And it
prevent the recompute later since the state is not write during the
loop.

closes odoo/odoo#122028

X-original-commit: b61d2ae58168fb479cce8de2a8c5f44d2ee020e0
Signed-off-by: William Henrotin (whe) <whe@odoo.com>
---
 addons/stock/models/stock_move_line.py | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/addons/stock/models/stock_move_line.py b/addons/stock/models/stock_move_line.py
index c936e3dadef5..d245b29e71f8 100644
--- a/addons/stock/models/stock_move_line.py
+++ b/addons/stock/models/stock_move_line.py
@@ -293,16 +293,20 @@ class StockMoveLine(models.Model):
             else:
                 create_move(move_line)
 
+        moves_to_update = mls.filtered(
+            lambda ml:
+            ml.move_id and
+            ml.qty_done and (
+                ml.move_id.state == 'done' or (
+                    ml.move_id.picking_id and
+                    ml.move_id.picking_id.immediate_transfer
+                ))
+        ).move_id
+        for move in moves_to_update:
+            move.with_context(avoid_putaway_rules=True).product_uom_qty = move.quantity_done
+
         for ml, vals in zip(mls, vals_list):
-            if ml.move_id and \
-                    ml.move_id.picking_id and \
-                    ml.move_id.picking_id.immediate_transfer and \
-                    ml.move_id.state != 'done' and \
-                    'qty_done' in vals:
-                ml.move_id.with_context(avoid_putaway_rules=True).product_uom_qty = ml.move_id.quantity_done
             if ml.state == 'done':
-                if 'qty_done' in vals:
-                    ml.move_id.product_uom_qty = ml.move_id.quantity_done
                 if ml.product_id.type == 'product':
                     Quant = self.env['stock.quant']
                     quantity = ml.product_uom_id._compute_quantity(ml.qty_done, ml.move_id.product_id.uom_id,rounding_method='HALF-UP')
-- 
GitLab