[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) <arm@odoo.com>
This commit is contained in:
Aurelien MARIE (auma)
2024-02-01 07:06:47 +00:00
parent 31f4e932c5
commit 42a72f6a20
2 changed files with 41 additions and 11 deletions
@@ -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()