From c6072b545c26340ea7a2c28189a0c6fda7c9c4fa Mon Sep 17 00:00:00 2001
From: "Benjamin Hanquin (beha)" <beha@odoo.com>
Date: Mon, 24 Jul 2023 13:34:54 +0200
Subject: [PATCH] [IMP] Stock Production Lot dissociate
 last_delivery_partner_id computation

In stock_production_lot model, there is a field last_delivery_partner_id which is displayed in a Tree View. This fields require to compute ALL the delivery_ids of each LOT, only to display the last_delivery_partner.

This implies a big performance issue for big lots with huge tracability needs in it. The idea is simple, dissociate the computation for delivery_ids, which is only used in Form View and the last_delivery_partner_id which is only used in the Tree View.

I do agree that if both are used in the same view, it would double the computation time. But currently there is a lot of useless computation. Currently the only way to mitigate is by removing the field last_delivery_partner_id in the Tree View, but if client needs that field, it doesn't works.

Benchmark

|Lots/Serial |# Lots | # Delivery | Before PR | After PR |
|:------------:|:---------:|:--------:|
|Lots| 3 | 3  | 0.2723 s |0.0091 s |
|Lots| 4 | 6699 | 307.98 s | 0.0059 s |
|Lots | 13 | 9575 | 569.85 | 0.0036 s |
|Serial | 80  | 80  | 0.30 s | 0.42 s |
|Serial | 150 | 150 |0.39 s | 0.51 s |
|Serial | 7000 | 2000 | 0.50 s/Batch of 1000 | 0.60 s/Batch of 1000|

closes odoo/odoo#133540

X-original-commit: 6852152e07c5cbfbb2e13e7902e1400e891a8401
Signed-off-by: William Henrotin (whe) <whe@odoo.com>
---
 addons/stock/models/stock_lot.py          | 16 +++++++++++-----
 addons/stock_dropshipping/models/stock.py |  4 ++--
 2 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/addons/stock/models/stock_lot.py b/addons/stock/models/stock_lot.py
index c0bdcaac4c68..a11110bc1de3 100644
--- a/addons/stock/models/stock_lot.py
+++ b/addons/stock/models/stock_lot.py
@@ -33,7 +33,7 @@ class StockLot(models.Model):
     company_id = fields.Many2one('res.company', 'Company', required=True, index=True, default=lambda self: self.env.company.id)
     delivery_ids = fields.Many2many('stock.picking', compute='_compute_delivery_ids', string='Transfers')
     delivery_count = fields.Integer('Delivery order count', compute='_compute_delivery_ids')
-    last_delivery_partner_id = fields.Many2one('res.partner', compute='_compute_delivery_ids')
+    last_delivery_partner_id = fields.Many2one('res.partner', compute='_compute_last_delivery_partner_id')
 
     @api.model
     def generate_lot_names(self, first_lot, count):
@@ -124,10 +124,16 @@ class StockLot(models.Model):
         for lot in self:
             lot.delivery_ids = delivery_ids_by_lot[lot.id]
             lot.delivery_count = len(lot.delivery_ids)
-            lot.last_delivery_partner_id = False
-            # If lot is serial, keep track of the latest delivery's partner
-            if lot.product_id.tracking == 'serial' and lot.delivery_count > 0:
-                lot.last_delivery_partner_id = lot.delivery_ids.sorted(key=attrgetter('date_done'), reverse=True)[0].partner_id
+
+    def _compute_last_delivery_partner_id(self):
+        serial_products = self.filtered(lambda l: l.product_id.tracking == 'serial')
+        delivery_ids_by_lot = serial_products._find_delivery_ids_by_lot()
+        (self - serial_products).last_delivery_partner_id = False
+        for lot in serial_products:
+            if lot.product_id.tracking == 'serial' and len(delivery_ids_by_lot[lot.id]) > 0:
+                lot.last_delivery_partner_id = self.env['stock.picking'].browse(delivery_ids_by_lot[lot.id]).sorted(key='date_done', reverse=True)[0].partner_id
+            else:
+                lot.last_delivery_partner_id = False
 
     @api.model_create_multi
     def create(self, vals_list):
diff --git a/addons/stock_dropshipping/models/stock.py b/addons/stock_dropshipping/models/stock.py
index 7e90b1f6767f..af6a566c5a8b 100644
--- a/addons/stock_dropshipping/models/stock.py
+++ b/addons/stock_dropshipping/models/stock.py
@@ -52,8 +52,8 @@ class StockPickingType(models.Model):
 class StockLot(models.Model):
     _inherit = 'stock.lot'
 
-    def _compute_delivery_ids(self):
-        super()._compute_delivery_ids()
+    def _compute_last_delivery_partner_id(self):
+        super()._compute_last_delivery_partner_id()
         for lot in self:
             if lot.delivery_count > 0:
                 last_delivery = max(lot.delivery_ids, key=lambda d: d.date_done)
-- 
GitLab