[FIX] stock: _action_done with OrderedSet for scalability
Make more scalable the `_action_done` by replacing recordset/union by OrderedSet/add. Also add `limit=1` in the lot search. opw-2374846 X-original-commit: ffe9f204474de832514ab6464947c607a4c92282
This commit is contained in:
@@ -5,6 +5,7 @@ from collections import Counter
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.tools import OrderedSet
|
||||
from odoo.tools.float_utils import float_compare, float_is_zero, float_round
|
||||
from odoo.addons.base.models.ir_model import MODULE_UNINSTALL_FLAG
|
||||
|
||||
@@ -431,9 +432,9 @@ class StockMoveLine(models.Model):
|
||||
# adjustment, enforce some rules on the `lot_id` field. If `qty_done` is null, we unlink
|
||||
# the line. It is mandatory in order to free the reservation and correctly apply
|
||||
# `action_done` on the next move lines.
|
||||
ml_to_delete = self.env['stock.move.line']
|
||||
ml_to_create_lot = self.env['stock.move.line']
|
||||
tracked_ml_without_lot = self.env['stock.move.line']
|
||||
ml_ids_tracked_without_lot = OrderedSet()
|
||||
ml_ids_to_delete = OrderedSet()
|
||||
ml_ids_to_create_lot = OrderedSet()
|
||||
for ml in self:
|
||||
# Check here if `ml.qty_done` respects the rounding of `ml.product_uom_id`.
|
||||
uom_qty = float_round(ml.qty_done, precision_rounding=ml.product_uom_id.rounding, rounding_method='HALF-UP')
|
||||
@@ -458,11 +459,11 @@ class StockMoveLine(models.Model):
|
||||
('company_id', '=', ml.company_id.id),
|
||||
('product_id', '=', ml.product_id.id),
|
||||
('name', '=', ml.lot_name),
|
||||
])
|
||||
], limit=1)
|
||||
if lot:
|
||||
ml.lot_id = lot.id
|
||||
else:
|
||||
ml_to_create_lot |= ml
|
||||
ml_ids_to_create_lot.add(ml.id)
|
||||
elif not picking_type_id.use_create_lots and not picking_type_id.use_existing_lots:
|
||||
# If the user disabled both `use_create_lots` and `use_existing_lots`
|
||||
# checkboxes on the picking type, he's allowed to enter tracked
|
||||
@@ -473,25 +474,29 @@ class StockMoveLine(models.Model):
|
||||
# tracked products without a `lot_id`.
|
||||
continue
|
||||
|
||||
if not ml.lot_id and ml not in ml_to_create_lot:
|
||||
tracked_ml_without_lot |= ml
|
||||
if not ml.lot_id and ml.id not in ml_ids_to_create_lot:
|
||||
ml_ids_tracked_without_lot.add(ml.id)
|
||||
elif qty_done_float_compared < 0:
|
||||
raise UserError(_('No negative quantities allowed'))
|
||||
else:
|
||||
ml_to_delete |= ml
|
||||
ml_ids_to_delete.add(ml.id)
|
||||
|
||||
if tracked_ml_without_lot:
|
||||
if ml_ids_tracked_without_lot:
|
||||
mls_tracked_without_lot = self.env['stock.move.line'].browse(ml_ids_tracked_without_lot)
|
||||
raise UserError(_('You need to supply a Lot/Serial Number for product: \n - ') +
|
||||
'\n - '.join(tracked_ml_without_lot.mapped('product_id.display_name')))
|
||||
'\n - '.join(mls_tracked_without_lot.mapped('product_id.display_name')))
|
||||
ml_to_create_lot = self.env['stock.move.line'].browse(ml_ids_to_create_lot)
|
||||
ml_to_create_lot._create_and_assign_production_lot()
|
||||
|
||||
ml_to_delete.unlink()
|
||||
mls_to_delete = self.env['stock.move.line'].browse(ml_ids_to_delete)
|
||||
mls_to_delete.unlink()
|
||||
|
||||
(self - ml_to_delete)._check_company()
|
||||
mls_todo = (self - mls_to_delete)
|
||||
mls_todo._check_company()
|
||||
|
||||
# Now, we can actually move the quant.
|
||||
done_ml = self.env['stock.move.line']
|
||||
for ml in self - ml_to_delete:
|
||||
ml_ids_to_ignore = OrderedSet()
|
||||
for ml in mls_todo:
|
||||
if ml.product_id.type == 'product':
|
||||
rounding = ml.product_uom_id.rounding
|
||||
|
||||
@@ -499,7 +504,8 @@ class StockMoveLine(models.Model):
|
||||
if not ml._should_bypass_reservation(ml.location_id) and float_compare(ml.qty_done, ml.product_uom_qty, precision_rounding=rounding) > 0:
|
||||
qty_done_product_uom = ml.product_uom_id._compute_quantity(ml.qty_done, ml.product_id.uom_id, rounding_method='HALF-UP')
|
||||
extra_qty = qty_done_product_uom - ml.product_qty
|
||||
ml._free_reservation(ml.product_id, ml.location_id, extra_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id, ml_to_ignore=done_ml)
|
||||
ml_to_ignore = self.env['stock.move.line'].browse(ml_ids_to_ignore)
|
||||
ml._free_reservation(ml.product_id, ml.location_id, extra_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id, ml_to_ignore=ml_to_ignore)
|
||||
# unreserve what's been reserved
|
||||
if not ml._should_bypass_reservation(ml.location_id) and ml.product_id.type == 'product' and ml.product_qty:
|
||||
try:
|
||||
@@ -518,9 +524,9 @@ class StockMoveLine(models.Model):
|
||||
Quant._update_available_quantity(ml.product_id, ml.location_id, -taken_from_untracked_qty, lot_id=False, package_id=ml.package_id, owner_id=ml.owner_id)
|
||||
Quant._update_available_quantity(ml.product_id, ml.location_id, taken_from_untracked_qty, lot_id=ml.lot_id, package_id=ml.package_id, owner_id=ml.owner_id)
|
||||
Quant._update_available_quantity(ml.product_id, ml.location_dest_id, quantity, lot_id=ml.lot_id, package_id=ml.result_package_id, owner_id=ml.owner_id, in_date=in_date)
|
||||
done_ml |= ml
|
||||
ml_ids_to_ignore.add(ml.id)
|
||||
# Reset the reserved quantity as we just moved it to the destination location.
|
||||
(self - ml_to_delete).with_context(bypass_reservation_update=True).write({
|
||||
mls_todo.with_context(bypass_reservation_update=True).write({
|
||||
'product_uom_qty': 0.00,
|
||||
'date': fields.Datetime.now(),
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user