From 42a72f6a207eb3c709640b015e3b81eddff816ad Mon Sep 17 00:00:00 2001 From: "Aurelien MARIE (auma)" Date: Thu, 14 Dec 2023 15:16:22 +0000 Subject: [PATCH] [PERF] mrp_subcontracting: Speed up confirmation of PO Current behavior: Confirming a Purchase Order with more than 50 lines takes too much time to be processed. In the case of the client they had PO with more than 200 lines which makes it impossible for them to confirm them. Step to reproduce: - Install mrp and mrp_subcontracting - Create PO with more than 50 order lines or more - Try to confirm it - Take a long time or timeout Benchmark (made in 16): | No. of PO lines | Before | After | |-----------------|:-------:|:------:| | 9 | 1s30 | 1s30 | | 91 | 1min | 16s | | 273 | 4min | 50s | | 405 | 4min30s | 1min6s | Fix: Batch more actions and records to reduce the number of queries generated by the ORM. opw-3625892 closes odoo/odoo#149830 X-original-commit: 7d9d7917948df966ada2055dcfead0cabaaf0651 Signed-off-by: Arnold Moyaux (arm) --- addons/mrp/models/mrp_production.py | 24 ++++++++++++---- .../models/stock_picking.py | 28 +++++++++++++++---- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py index 014e30da301..17e6188d200 100644 --- a/addons/mrp/models/mrp_production.py +++ b/addons/mrp/models/mrp_production.py @@ -1394,12 +1394,16 @@ class MrpProduction(models.Model): def action_confirm(self): self._check_company() + moves_ids_to_confirm = set() + move_raws_ids_to_adjust = set() + workorder_ids_to_confirm = set() for production in self: + production_vals = {} if production.bom_id: - production.consumption = production.bom_id.consumption + production_vals.update({'consumption': production.bom_id.consumption}) # In case of Serial number tracking, force the UoM to the UoM of product if production.product_tracking == 'serial' and production.product_uom_id != production.product_id.uom_id: - production.write({ + production_vals.update({ 'product_qty': production.product_uom_id._compute_quantity(production.product_qty, production.product_id.uom_id), 'product_uom_id': production.product_id.uom_id }) @@ -1408,9 +1412,19 @@ class MrpProduction(models.Model): 'product_uom_qty': move_finish.product_uom._compute_quantity(move_finish.product_uom_qty, move_finish.product_id.uom_id), 'product_uom': move_finish.product_id.uom_id }) - production.move_raw_ids._adjust_procure_method() - (production.move_raw_ids | production.move_finished_ids)._action_confirm(merge=False) - production.workorder_ids._action_confirm() + if production_vals: + production.write(production_vals) + move_raws_ids_to_adjust.update(production.move_raw_ids.ids) + moves_ids_to_confirm.update((production.move_raw_ids | production.move_finished_ids).ids) + workorder_ids_to_confirm.update(production.workorder_ids.ids) + + move_raws_to_adjust = self.env['stock.move'].browse(sorted(move_raws_ids_to_adjust)) + moves_to_confirm = self.env['stock.move'].browse(sorted(moves_ids_to_confirm)) + workorder_to_confirm = self.env['mrp.workorder'].browse(sorted(workorder_ids_to_confirm)) + + move_raws_to_adjust._adjust_procure_method() + moves_to_confirm._action_confirm(merge=False) + workorder_to_confirm._action_confirm() # run scheduler for moves forecasted to not have enough in stock self.move_raw_ids._trigger_scheduler() self.picking_ids.filtered( diff --git a/addons/mrp_subcontracting/models/stock_picking.py b/addons/mrp_subcontracting/models/stock_picking.py index 150b1369ad0..8748ff8af6e 100644 --- a/addons/mrp_subcontracting/models/stock_picking.py +++ b/addons/mrp_subcontracting/models/stock_picking.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. - +from collections import defaultdict from datetime import timedelta from odoo import api, fields, models, _ @@ -149,6 +149,8 @@ class StockPicking(models.Model): def _subcontracted_produce(self, subcontract_details): self.ensure_one() + group_move = defaultdict(list) + group_by_company = defaultdict(list) for move, bom in subcontract_details: # do not create extra production for move that have their quantity updated if move.move_orig_ids.production_id: @@ -157,11 +159,25 @@ class StockPicking(models.Model): if float_compare(quantity, 0, precision_rounding=move.product_uom.rounding) <= 0: # If a subcontracted amount is decreased, don't create a MO that would be for a negative value. continue - mo = self.env['mrp.production'].with_company(move.company_id).create(self._prepare_subcontract_mo_vals(move, bom)) - mo.date_finished = move.date # Avoid to have the picking late depending of the MO - mo.action_confirm() - # Link the finished to the receipt move. + mo_subcontract = self._prepare_subcontract_mo_vals(move, bom) + # Link the move to the id of the MO's procurement group + group_move[mo_subcontract['procurement_group_id']] = move + # Group the MO by company + group_by_company[move.company_id.id].append(mo_subcontract) + + all_mo = set() + for company, group in group_by_company.items(): + grouped_mo = self.env['mrp.production'].with_company(company).create(group) + all_mo.update(grouped_mo.ids) + + all_mo = self.env['mrp.production'].browse(sorted(all_mo)) + all_mo.action_confirm() + + for mo in all_mo: + move = group_move[mo.procurement_group_id.id][0] + mo.write({'date_finished': move.date}) finished_move = mo.move_finished_ids.filtered(lambda m: m.product_id == move.product_id) finished_move.write({'move_dest_ids': [(4, move.id, False)]}) - mo.action_assign() + + all_mo.action_assign()