Tuesday, June 9, 2026
4 changes · 19.0
Enhancements to existing features
Odoo's command-line database restore now offers a move option that preserves the database identity instead of creating a new one. This helps customers move Enterprise databases between servers without accidentally deregistering their subscription, while the default copy behavior remains unchanged.
Original PR description
### What & why `odoo db load` always calls `restore_db(..., copy=True)`, which forces the generation of a new `dbuuid` via `ir.config_parameter.init(force=True)`. That is the right default when…
### What & why `odoo db load` always calls `restore_db(..., copy=True)`, which forces the generation of a new `dbuuid` via `ir.config_parameter.init(force=True)`. That is the right default when *duplicating* a database, but it breaks the intended behaviour when *moving* a database between servers: Enterprise subscription codes are registered against the database UUID, so regenerating it deregisters the moved database. The web database manager already lets the user choose between copying and moving (the `copy` flag of the `/web/database/restore` route), but the CLI exposed no equivalent and forced a copy unconditionally. The CLI is the better tool for server-to-server moves: it isn't subject to reverse-proxy upload/timeout limits and can run unattended or interactively. ### Steps to reproduce the current limitation 1. On server A: `odoo db dump mydb mydb.zip` (Enterprise DB registered to its UUID) 2. On server B: `odoo db load mydb mydb.zip` 3. `database.uuid` has changed → the subscription is deregistered ### Fix Add a `--move` flag to `odoo db load` that maps to `restore_db(copy=False)`, keeping the original UUID. The default remains `copy=True`, so existing behaviour is unchanged. ```sh odoo db load mydb mydb.zip # unchanged: restore as a copy (new UUID) odoo db load --move mydb mydb.zip # new: restore as a move (keep the UUID) ``` ### Backport request This would be greatly appreciated as a backport to 18.0, 17.0, and 16.0 as well. Those are precisely the versions that ship the `odoo db` CLI subcommand, so the fix is applicable to all of them — which is why the backport range is 16.0 → 19.0 and stops at 16.0. Forward-Port-Of: odoo/odoo#268501
Supplier-related fields now load much faster when reviewing many replenishment orderpoints. This reduces database work and improves response times for purchasing and dropshipping workflows without changing business behavior.
Original PR description
Currently, computing effective_vendor_id and supplier_id_placeholder presents N+1 query issues. Since every call to _get_default_rule() eventually triggers a _read_group() in _search_rule_for_warehouses(). However we can get rid of this entirely, since the subsequent call to _get_matching_supplier() with an empty values dict depends entirely on the product and not the rule. Another query is also avoided in _get_matching_supplier() which eventually calls ref(). ref() can be substituted with the private method since we are checking against the rule's existing route_id. Benchmark web_search_read by effective_vendor_id on 12,000 orderpoints | |Query Count|Exec Time| |------|-----------|---------| |Before|15,519 |17.46s | |After |722 |3.21s | opw-6186351
Employee leave balance forecasts now avoid repeated background recalculations that could make some requests extremely slow. This significantly improves response times for employees with accrual-based time off, especially when future leave requests are involved.
Original PR description
## The Problem When computing a future leave balance, `_get_future_leaves_on` triggers `_process_accrual_plans`, which iterates period by period and calls `_get_leaves_taken` at each step.…
## The Problem When computing a future leave balance, `_get_future_leaves_on` triggers `_process_accrual_plans`, which iterates period by period and calls `_get_leaves_taken` at each step. `_get_leaves_taken` re-enters `_get_consumed_leaves` with `ignore_future=True`, but other accrual allocations on the same employee were not guarded by `precomputed_allocations`, causing `_get_future_leaves_on` to fire again for each of them, launching another full accrual run recursively. With N periods and K allocations, total work grew as $O(N^K)$. ## The Solution Adding `not ignore_future` to the guard prevents future projection in any nested context where it is both semantically incorrect and the source of the blowup. --- ## Benchmarks *Tested on a customer database with an employee having 2 accrual allocations and pending future leave requests 6 months out:* | | Queries | Request Time | Improvement | | :--- | :--- | :--- | :--- | | **Before** | 220K | 145.0s | — | | **After** | 2.7K | 2.8s | **-98%** | **Note:** More optimizations could be done to reduce the queries to a constant. However given the current design, it would be a bit big change and the current performance is already acceptable. **OPW-6115804**
Improves performance when opening the reconciliation widget for multiple accounting lines by checking access permissions in batches instead of one line at a time. This reduces unnecessary processing and should make reconciliation workflows feel more responsive for users.
Original PR description
When assigning a value in batch, the ORM doesn't manage to batch the call to `check_access` done in `write_batch`/`write_real` because each write is done individually when setting a value in the compute function. This field is especially annoying because it is read when opening the reconciliation widget on several lines.