[FIX] mrp: speedup _post_inventory for MO batches

Rewrite _post_inventory to make it work better
with mo batches. This mainly improves the
time it takes to mark_as_done manufacturing
orders from the Workorders ListView.

stock.move._action_done is faster
when called outside of a for loop, i.e.
directly on self.

opw-2760394

closes odoo/odoo#84846

X-original-commit: 4cc6083ea1bd28be07e275322481ad11d8995d58
Signed-off-by: William Henrotin (whe) <whe@odoo.com>
This commit is contained in:
Aurélien (avd)
2022-02-18 10:46:57 +00:00
parent 8d591ee3e2
commit 34c192761f
+22 -16
View File
@@ -13,7 +13,7 @@ from dateutil.relativedelta import relativedelta
from odoo import api, fields, models, _, Command
from odoo.exceptions import UserError, ValidationError
from odoo.tools import float_compare, float_round, float_is_zero, format_datetime
from odoo.tools.misc import OrderedSet, format_date
from odoo.tools.misc import OrderedSet, format_date, groupby as tools_groupby
from odoo.addons.stock.models.stock_move import PROCUREMENT_PRIORITIES
@@ -1439,27 +1439,33 @@ class MrpProduction(models.Model):
return True
def _post_inventory(self, cancel_backorder=False):
moves_to_do, moves_not_to_do = set(), set()
for move in self.move_raw_ids:
if move.state == 'done':
moves_not_to_do.add(move.id)
elif move.state != 'cancel':
moves_to_do.add(move.id)
if move.product_qty == 0.0 and move.quantity_done > 0:
move.product_uom_qty = move.quantity_done
self.env['stock.move'].browse(moves_to_do)._action_done(cancel_backorder=cancel_backorder)
moves_to_do = self.move_raw_ids.filtered(lambda x: x.state == 'done') - self.env['stock.move'].browse(moves_not_to_do)
# Create a dict to avoid calling filtered inside for loops.
moves_to_do_by_order = defaultdict(lambda: self.env['stock.move'], [
(key, self.env['stock.move'].concat(*values))
for key, values in tools_groupby(moves_to_do, key=lambda m: m.raw_material_production_id.id)
])
for order in self:
moves_not_to_do = order.move_raw_ids.filtered(lambda x: x.state == 'done')
moves_to_do = order.move_raw_ids.filtered(lambda x: x.state not in ('done', 'cancel'))
for move in moves_to_do.filtered(lambda m: m.product_qty == 0.0 and m.quantity_done > 0):
move.product_uom_qty = move.quantity_done
# MRP do not merge move, catch the result of _action_done in order
# to get extra moves.
moves_to_do = moves_to_do._action_done(cancel_backorder=cancel_backorder)
moves_to_do = order.move_raw_ids.filtered(lambda x: x.state == 'done') - moves_not_to_do
finish_moves = order.move_finished_ids.filtered(lambda m: m.product_id == order.product_id and m.state not in ('done', 'cancel'))
# the finish move can already be completed by the workorder.
if not finish_moves.quantity_done:
finish_moves.quantity_done = float_round(order.qty_producing - order.qty_produced, precision_rounding=order.product_uom_id.rounding, rounding_method='HALF-UP')
finish_moves.move_line_ids.lot_id = order.lot_producing_id
order._cal_price(moves_to_do)
moves_to_finish = order.move_finished_ids.filtered(lambda x: x.state not in ('done', 'cancel'))
moves_to_finish = moves_to_finish._action_done(cancel_backorder=cancel_backorder)
order.action_assign()
consume_move_lines = moves_to_do.mapped('move_line_ids')
order._cal_price(moves_to_do_by_order[order.id])
moves_to_finish = self.move_finished_ids.filtered(lambda x: x.state not in ('done', 'cancel'))
moves_to_finish = moves_to_finish._action_done(cancel_backorder=cancel_backorder)
self.action_assign()
for order in self:
consume_move_lines = moves_to_do_by_order[order.id].mapped('move_line_ids')
order.move_finished_ids.move_line_ids.consume_line_ids = [(6, 0, consume_move_lines.ids)]
return True