Thursday, July 30, 2026
2 changes · 19.0
Resolved issues and error corrections
This update prevents a Python 3.13 behavior from severely slowing down Odoo's core model access during registry setup. It keeps test runs and day-to-day ORM operations from becoming significantly slower, while safely doing nothing on older Python versions where the workaround is not needed.
Original PR description
Backport of #275640 Despite resolving the conflicts (file moved) this version also checks the python version since PyUnstable_Type_AssignVersionTag does not exists in python 3.10 To be safer, the whole logic is skipped if python < 3.13 Forward-Port-Of: odoo/odoo#277697
Inventory Valuation now avoids processing kit products that should not be valued individually, preventing pages from hanging in databases with many kits. This improves reliability and response times for businesses managing large manufacturing or stock catalogs.
Original PR description
to reproduce: ============= - Have a database with a large number of kit BoMs (e.g. ~160k phantom mrp.bom records). - Open Inventory Valuation. - The request never returns and hangs forever. problem:…
to reproduce:
=============
- Have a database with a large number of kit BoMs (e.g. ~160k phantom
mrp.bom records).
- Open Inventory Valuation.
- The request never returns and hangs forever.
problem:
========
Commit 11e9c1297439 started searching the valued products with
`('qty_available', '!=', 0)`. On `product.product` this triggers the mrp
override `_search_qty_available_new`, which loads every phantom BoM in the
database and computes `qty_available` (via BoM explode) for each kit. On top
of that, the override builds the kit products recordset with repeated
`kit_products |= ...` unions, which is O(n^2). With a large catalog of kits
the combination of O(n) heavy explodes and O(n^2) unions never returns.
On top of the performance issue, the new search dropped the kit exclusion
that `_get_accounts_by_product` previously applied through
`_get_valuation_product_domain` (`('is_kits', '=', False)` in mrp_account),
so phantom products - which are never valued on their own - were wrongly
pulled into the valuation.
solution:
=========
Restore the kit exclusion: search the valued products through
`_get_valuation_product_domain()` (which adds `('is_kits', '=', False)` in
mrp_account) instead of the ad-hoc `('is_storable', '=', True)` domain, so
phantom products are no longer valued.
Add a `skip_kit_qty_available` context key on `_search_qty_available_new` so
callers that intentionally exclude kits can skip the costly kit BoM expansion
and return the base (quant-based) result directly. The key is set in
mrp_account (via `_get_valuation_product_context`), alongside the domain that
already excludes kits, so the optimization and its precondition stay in the
same layer.
Also make the remaining kit path in `_search_qty_available_new` scale: build
the kit products recordset in a single pass instead of O(n^2) recordset
unions, and use a set for membership checks.
Benchmark:
==========
for `_get_report_data()` (averaged over 5 runs):
| # Input data (phantom kits) | Before PR | After PR |
| :---: | :---: | :---: |
| 1,000 | 2.558 s | 35.5 ms |
| 5,000 | 10.991 s | 41.6 ms |
| 10,000 | 20.869 s | 66.0 ms |
| 25,000 | 61.807 s | 80.7 ms |
| 50,000 | 195.382 s | 87.9 ms |
the improvement is **~99% faster**
opw-6312168
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr