[FIX] delivery: read_group fest speeding up weights compute
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) <whe@odoo.com> Signed-off-by: Van Delft Aurélien (avd) <avd@odoo.com>
This commit is contained in:
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user