From 81773cd70fb3457b68ce490059a7a812920c8343 Mon Sep 17 00:00:00 2001 From: "Aurelien van Delft (avd)" Date: Thu, 8 Dec 2022 14:37:47 +0000 Subject: [PATCH] [FIX] delivery: read_group fest speeding up weights compute MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently _compute_bulk_weight and _compute_weight are going through each picking in self and each stock_move_line in picking.move_line_ids to compute the pickings' weight. This can be slow when there are lots of move_lines by pickings as the field cache will be filled by the move_lines records and uom._compute_quantity will be called once by move_line. This is especially true for pickings with SN-tracked products. For SN tracked products there will be one move_line by product_qty (so a picking with 1 SN tracked product with a qty of 100 will have 100 move_lines). In this case doing a read_group yields the highest speedup. Following the same reasoning a search_count is done in _compute_packages before retrieving package.move_line_ids. When package.move_line_ids.result_package_id is empty doing a count is much faster as it avoids calling _in_cache_without for the package move_line_ids. The search_count overhead is negligeable in the other case so adding it leads to an overall speedup on average. opw-3017013 closes odoo/odoo#107994 X-original-commit: c95abbe8fa09decca2f94a035934e8d6ae7903e1 Signed-off-by: William Henrotin (whe) Signed-off-by: Van Delft Aurélien (avd) --- addons/delivery/models/stock_picking.py | 59 +++++++++++++++++-------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/addons/delivery/models/stock_picking.py b/addons/delivery/models/stock_picking.py index 88a7ec41610..1efeffbbc03 100644 --- a/addons/delivery/models/stock_picking.py +++ b/addons/delivery/models/stock_picking.py @@ -2,6 +2,7 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. import json +from collections import defaultdict from odoo import models, fields, api, _ from odoo.exceptions import UserError @@ -13,22 +14,31 @@ class StockQuantPackage(models.Model): @api.depends('quant_ids', 'package_type_id') def _compute_weight(self): + if self.env.context.get('picking_id'): + package_weights = defaultdict(float) + # Ordering by qty_done prevents the default ordering by groupby fields that can inject multiple Left Joins in the resulting query. + res_groups = self.env['stock.move.line'].read_group( + [('result_package_id', 'in', self.ids), ('product_id', '!=', False), ('picking_id', '=', self.env.context['picking_id'])], + ['id:count'], + ['result_package_id', 'product_id', 'product_uom_id', 'qty_done'], + lazy=False, orderby='qty_done asc' + ) + for res_group in res_groups: + product_id = self.env['product.product'].browse(res_group['product_id'][0]) + product_uom_id = self.env['uom.uom'].browse(res_group['product_uom_id'][0]) + package_weights[res_group['result_package_id'][0]] += ( + res_group['__count'] + * product_uom_id._compute_quantity(res_group['qty_done'], product_id.uom_id) + * product_id.weight + ) for package in self: - # set initial weight to package type base weight weight = package.package_type_id.base_weight or 0.0 if self.env.context.get('picking_id'): - # TODO: potential bottleneck: N packages = N queries, use groupby ? - current_picking_move_line_ids = self.env['stock.move.line'].search([ - ('result_package_id', '=', package.id), - ('picking_id', '=', self.env.context['picking_id']) - ]) - for ml in current_picking_move_line_ids: - weight += ml.product_uom_id._compute_quantity( - ml.qty_done, ml.product_id.uom_id) * ml.product_id.weight + package.weight = weight + package_weights[package.id] else: for quant in package.quant_ids: weight += quant.quantity * quant.product_id.weight - package.weight = weight + package.weight = weight def _get_default_weight_uom(self): return self.env['product.template']._get_weight_uom_name_from_ir_config_parameter() @@ -59,19 +69,32 @@ class StockPicking(models.Model): def _compute_packages(self): for package in self: packs = set() - for move_line in package.move_line_ids: - if move_line.result_package_id: - packs.add(move_line.result_package_id.id) + if self.env['stock.move.line'].search_count([('picking_id', '=', package.id), ('result_package_id', '!=', False)]): + for move_line in package.move_line_ids: + if move_line.result_package_id: + packs.add(move_line.result_package_id.id) package.package_ids = list(packs) @api.depends('move_line_ids', 'move_line_ids.result_package_id', 'move_line_ids.product_uom_id', 'move_line_ids.qty_done') def _compute_bulk_weight(self): + picking_weights = defaultdict(float) + # Ordering by qty_done prevents the default ordering by groupby fields that can inject multiple Left Joins in the resulting query. + res_groups = self.env['stock.move.line'].read_group( + [('picking_id', 'in', self.ids), ('product_id', '!=', False), ('result_package_id', '=', False)], + ['id:count'], + ['picking_id', 'product_id', 'product_uom_id', 'qty_done'], + lazy=False, orderby='qty_done asc' + ) + for res_group in res_groups: + product_id = self.env['product.product'].browse(res_group['product_id'][0]) + product_uom_id = self.env['uom.uom'].browse(res_group['product_uom_id'][0]) + picking_weights[res_group['picking_id'][0]] += ( + res_group['__count'] + * product_uom_id._compute_quantity(res_group['qty_done'], product_id.uom_id) + * product_id.weight + ) for picking in self: - weight = 0.0 - for move_line in picking.move_line_ids: - if move_line.product_id and not move_line.result_package_id: - weight += move_line.product_uom_id._compute_quantity(move_line.qty_done, move_line.product_id.uom_id) * move_line.product_id.weight - picking.weight_bulk = weight + picking.weight_bulk = picking_weights[picking.id] @api.depends('move_line_ids.result_package_id', 'move_line_ids.result_package_id.shipping_weight', 'weight_bulk') def _compute_shipping_weight(self):