From 073b7bb944b5fcb7f978f1f8094e308b9d2bf9a4 Mon Sep 17 00:00:00 2001 From: Adrian Torres Date: Tue, 12 Mar 2019 13:14:26 +0000 Subject: [PATCH] [FIX] stock: unlink move_lines in batch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before this patch, cancelling a PO of 2000 lines would take a **very, very** long time to process... so long that I terminated it before it finished... yikes. This was due to the call to `_do_unreserve` on every single move when calling `_action_cancel`, this meant that n² calls to unlink where being made (at least), which also meant n² calls to `stock.move._recompute_state` were being made... that's a lot of recomputes... = bad performance The patch simply calls unlink once, which means `_recompute_state` is called only once, saving a lot of time. Cancel time for a PO containing 2000 lines: - Before patch: 1h30min+ (process terminated before finishing) - After patch: 7min Other modules making use of stock and `_action_cancel` should also see benefits from this patch closes odoo/odoo#31787 Signed-off-by: Arnold Moyaux --- addons/stock/models/stock_move.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index f3bf3bae039..feec9ba4f14 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -1014,10 +1014,12 @@ class StockMove(models.Model): def _action_cancel(self): if any(move.state == 'done' for move in self): raise UserError(_('You cannot cancel a stock move that has been set to \'Done\'.')) - for move in self: - if move.state == 'cancel': - continue - move._do_unreserve() + moves_to_cancel = self.filtered(lambda m: m.state != 'cancel') + # self cannot contain moves that are either cancelled or done, therefore we can safely + # unlink all associated move_line_ids + moves_to_cancel._do_unreserve() + + for move in moves_to_cancel: siblings_states = (move.move_dest_ids.mapped('move_orig_ids') - move).mapped('state') if move.propagate: # only cancel the next move if all my siblings are also cancelled