[IMP] stock: improve scalability of _action_assign

Replace union of RecordSet by union of OrderedSet to reduce the
complexity and improve the scalability. It can be a bottleneck to
huge number of move to assign.

task-2390516

X-original-commit: e89105144a34ee73981db383ac0625dcaf63b27b
This commit is contained in:
Rémy Voet (ryv)
2021-01-22 15:49:11 +00:00
parent 4fa1f28cd0
commit 17f723a7d4
+13 -12
View File
@@ -1272,8 +1272,9 @@ class StockMove(models.Model):
equal to its `product_qty`. If it is less, the stock move is considered
partially available.
"""
assigned_moves = self.env['stock.move']
partially_available_moves = self.env['stock.move']
StockMove = self.env['stock.move']
assigned_moves_ids = OrderedSet()
partially_available_moves_ids = OrderedSet()
# Read the `reserved_availability` field of the moves out of the loop to prevent unwanted
# cache invalidation when actually reserving the move.
reserved_availability = {move: move.reserved_availability for move in self}
@@ -1300,17 +1301,17 @@ class StockMove(models.Model):
to_update[0].product_uom_qty += missing_reserved_uom_quantity
else:
move_line_vals_list.append(move._prepare_move_line_vals(quantity=missing_reserved_quantity))
assigned_moves |= move
assigned_moves_ids.add(move.id)
else:
if float_is_zero(move.product_uom_qty, precision_rounding=move.product_uom.rounding):
assigned_moves |= move
assigned_moves_ids.add(move.id)
elif not move.move_orig_ids:
if move.procure_method == 'make_to_order':
continue
# If we don't need any quantity, consider the move assigned.
need = missing_reserved_quantity
if float_is_zero(need, precision_rounding=rounding):
assigned_moves |= move
assigned_moves_ids.add(move.id)
continue
# Reserve new quants and create move lines accordingly.
forced_package_id = move.package_level_id.package_id or None
@@ -1321,9 +1322,9 @@ class StockMove(models.Model):
if float_is_zero(taken_quantity, precision_rounding=rounding):
continue
if float_compare(need, taken_quantity, precision_rounding=rounding) == 0:
assigned_moves |= move
assigned_moves_ids.add(move.id)
else:
partially_available_moves |= move
partially_available_moves_ids.add(move.id)
else:
# Check what our parents brought and what our siblings took in order to
# determine what we can distribute.
@@ -1348,7 +1349,7 @@ class StockMove(models.Model):
# As we defer the write on the stock.move's state at the end of the loop, there
# could be moves to consider in what our siblings already took.
moves_out_siblings = move.move_orig_ids.mapped('move_dest_ids') - move
moves_out_siblings_to_consider = moves_out_siblings & (assigned_moves + partially_available_moves)
moves_out_siblings_to_consider = moves_out_siblings & (StockMove.browse(assigned_moves_ids) + StockMove.browse(partially_available_moves_ids))
reserved_moves_out_siblings = moves_out_siblings.filtered(lambda m: m.state in ['partially_available', 'assigned'])
move_lines_out_reserved = (reserved_moves_out_siblings | moves_out_siblings_to_consider).mapped('move_line_ids')
keys_out_groupby = ['location_id', 'lot_id', 'package_id', 'owner_id']
@@ -1388,15 +1389,15 @@ class StockMove(models.Model):
if float_is_zero(taken_quantity, precision_rounding=rounding):
continue
if float_is_zero(need - taken_quantity, precision_rounding=rounding):
assigned_moves |= move
assigned_moves_ids.add(move.id)
break
partially_available_moves |= move
partially_available_moves_ids.add(move.id)
if move.product_id.tracking == 'serial':
move.next_serial_count = move.product_uom_qty
self.env['stock.move.line'].create(move_line_vals_list)
partially_available_moves.write({'state': 'partially_available'})
assigned_moves.write({'state': 'assigned'})
StockMove.browse(partially_available_moves_ids).write({'state': 'partially_available'})
StockMove.browse(assigned_moves_ids).write({'state': 'assigned'})
if self.env.context.get('bypass_entire_pack'):
return
self.mapped('picking_id')._check_entire_pack()