From ee2fe22db8dcc54d05be89184dd96df6aa9d7148 Mon Sep 17 00:00:00 2001 From: "Tiffany Chang (tic)" Date: Tue, 7 Nov 2023 13:29:47 +0100 Subject: [PATCH] [FIX] stock: optimize _search_product_qty The existing `_search_product_qty` was not scaleable for dbs with many lots, therefore we optimize it to be more clever. Also add in the missing operator/value checks. closes odoo/odoo#126795 Signed-off-by: Tiffany Chang (tic) --- addons/stock/models/stock_lot.py | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/addons/stock/models/stock_lot.py b/addons/stock/models/stock_lot.py index ef2f0a13bb6..2c226e5f530 100644 --- a/addons/stock/models/stock_lot.py +++ b/addons/stock/models/stock_lot.py @@ -176,19 +176,35 @@ class StockLot(models.Model): lot.product_qty = sum(quants.mapped('quantity')) def _search_product_qty(self, operator, value): + if operator not in OPERATORS: + raise UserError(_("Invalid domain operator %s", operator)) + if not isinstance(value, (float, int)): + raise UserError(_("Invalid domain right operand '%s'. It must be of type Integer/Float", value)) domain = [ ('lot_id', '!=', False), '|', ('location_id.usage', '=', 'internal'), '&', ('location_id.usage', '=', 'transit'), ('location_id.company_id', '!=', False) ] - lots_w_qty = { - id: qty for id, qty in map(lambda l: (l['lot_id'][0], l['quantity']), self.env['stock.quant'].read_group(domain=domain, fields=['quantity:sum'], groupby=['lot_id'])) - } - all_lots = self.env['stock.lot'].search([]) + lots_w_qty = self.env['stock.quant']._read_group(domain=domain, groupby=['lot_id'], aggregates=['quantity:sum'], having=[('quantity:sum', '!=', 0)]) ids = [] - for lot in all_lots: - if OPERATORS[operator](lots_w_qty.get(lot.id, 0), value): - ids.append(lot.id) + lot_ids_w_qty = [] + for lot, quantity_sum in lots_w_qty: + lot_id = lot.id + lot_ids_w_qty.append(lot_id) + if OPERATORS[operator](quantity_sum, value): + ids.append(lot_id) + if value == 0.0 and operator == '=': + return [('id', 'not in', lot_ids_w_qty)] + if value == 0.0 and operator == '!=': + return [('id', 'in', lot_ids_w_qty)] + # check if we need include zero values in result + include_zero = ( + value < 0.0 and operator in ('>', '>=') or + value > 0.0 and operator in ('<', '<=') or + value == 0.0 and operator in ('>=', '<=') + ) + if include_zero: + return ['|', ('id', 'in', ids), ('id', 'not in', lot_ids_w_qty)] return [('id', 'in', ids)] def action_lot_open_quants(self):