Daily updates from Odoo
Saturday, August 8, 2026
6 changes · 18.0
Enhancements to existing features
Budget report loading has been optimized by changing how budget lines are matched to related accounting data. This reduces very slow report loads on larger databases, improving usability for teams working with many budget and analytic records.
Original PR description
**Description:** While loading the budget report, the bad queries are created by ```def _get_aal_query()``` and ```def _get_pol_query()``` function, makes the budget report unusable. **Root cause:**…
**Description:**
While loading the budget report, the bad queries are created by
```def _get_aal_query()``` and ```def _get_pol_query()``` function, makes
the budget report unusable.
**Root cause:**
Instead of doing a hash join while searching the record,
the OR statement in the Left Join in the condition
```(%(bl)s IS NULL OR %(a)s = %(bl)s)```
creates a nested for loop that compares everything single aal to bl,
this causes a significant performance issue as the number of the
number of check will be the the number aal * bl,
if a database has a 70k aal and 20k bl, both numbers are not large
but it will cause a 70k * 20k search which is more than a billion.
**Fix**:
There are some refactors made in this PR.
_First_, separate out the Q1.
In order to find the aal that has no bl connects to it.
Doing a search to find the aals that have bl and then subtract them from all aals.
_Second_, Instead of doing a nested loop for by using
```(%(bl)s IS NULL OR %(a)s = %(bl)s)```,
originally we will have do something like
```
JOIN budget_line bl
ON (bl.x_plan2_id IS NULL OR aal.x_plan2_id = bl.x_plan2_id)
AND (bl.x_plan3_id IS NULL OR aal.x_plan3_id = bl.x_plan3_id)
AND (bl.x_plan4_id IS NULL OR aal.x_plan4_id = bl.x_plan4_id)
```
Assuming each bl has three plans ```x_plan2_id```, ```x_plan3_id```, ```x_plan4_id```
Grouping the bl base on whether a specific plan is set, (i.e. shapes)
we can skip the ```IS NULL OR``` because we already know which plan
is null and do the hash join directly.
For example, the shapes will be a dictionary with a key of a tuple of booleans
based on whether a plan is set or not and the value is a list of bl_id.
```
{
(True, False, False): [1, 2],
(False, True, True): [3, 4],
(False, False, False): [5],
}
```
we can end up doing something like
```
JOIN budget_line bl
ON bl.id = ANY(ARRAY[3,4])
AND aal.x_plan3_id = bl.x_plan3_id AND aal.x_plan4_id = bl.x_plan4_id
```
which is way more faster.
---
The benchmark is made locally from this client's database which contains
69k aal, 23k bl, 6829 pol and 3 plans for aal and bl.
|Record count |Time before|Time after|
|--------------------------------------------------|-----------------|---------------|
|69k aal, 23k bl, 6829 pol, 3 plans |70.04s |4.6s |
Dalibo:
Before:
Month-over-month grand total by company:
https://explain.dalibo.com/plan/8h3d4e89aaf9f3d4
Overall grand total by company:
https://explain.dalibo.com/plan/445g1f9caf4923e2
Month-over-month grand total by plan:
https://explain.dalibo.com/plan/53a138ca50b2a7c4
Overall grand total by plan:
https://explain.dalibo.com/plan/hdbe169ddc7g5785
After:
Month-over-month grand total by company:
https://explain.dalibo.com/plan/hcc86c801e6872bf
Overall grand total by company:
https://explain.dalibo.com/plan/69b2421a3581f98h
Month-over-month grand total by plan:
https://explain.dalibo.com/plan/a88f398bbbch3148
Overall grand total by plan:
https://explain.dalibo.com/plan/1gg749ae7ab1553c
opw-6345552Resolved issues and error corrections
This fix ensures Belgian payroll reports the correct mobility budget balance when it is paid after the related contract no longer has an active mobility budget. It uses the previous quarter's contract information so declarations avoid incorrectly showing a zero amount.
Original PR description
When the mobility budget balance is paid on a contract that no longer carries a mobility budget, fall back to the previous quarter's contract to declare the correct amount instead of 0. Task-6384786
Steps to reproduce: - Create a sale order with a down payment term. - Invoice the down payment (down payment invoice A). - Credit that down payment invoice directly (credit note A), without reconciling it with anything else. - Generate the FatturaPA XML for credit note A. - Observe that DatiFattureCollegate lists both down payment invoice A and credit note A itself, instead of only down payment invoice A. On an order with several down payment invoices/credit notes over time, every one of th
Original PR description
Steps to reproduce: - Create a sale order with a down payment term. - Invoice the down payment (down payment invoice A). - Credit that down payment invoice directly (credit note A), without…
Steps to reproduce: - Create a sale order with a down payment term. - Invoice the down payment (down payment invoice A). - Credit that down payment invoice directly (credit note A), without reconciling it with anything else. - Generate the FatturaPA XML for credit note A. - Observe that DatiFattureCollegate lists both down payment invoice A and credit note A itself, instead of only down payment invoice A. On an order with several down payment invoices/credit notes over time, every one of them is listed instead of just the document the current credit note actually reverses. Cause of the issue: _l10n_it_edi_export_data built downpayment_moves from self.invoice_line_ids._get_downpayment_lines().move_id with no filtering. _get_downpayment_lines() (sale override) returns every invoice line ever created against the same down payment sale order line, across the whole life of the order, not just the invoice the current document actually relates to. The template renders DatiFattureCollegate for every one of those moves unconditionally, on top of the already-correct reversed_entry_id/reconciled_moves fallback, including the current document itself. Solution: Restrict downpayment_moves to lines with a negative price_subtotal, mirroring the existing down payment deduction-line detection a few lines above, and explicitly exclude the current document. This limits DatiFattureCollegate's down payment entries to the case they are meant for: a final invoice actually deducting a previously invoiced down payment. opw-6429716
**Steps to Reproduce:** 1. Send a message to Marc demo with Mitchell admin or vice-versa, read the message from reciever's side. 2. Click on seen-by indicator from sender's side, make sure the dialog appears and then Press `'ESC'`. 3. Chat window closes whereas the dialog should have closed. Since #169737, pressing 'esc' on the seen-by dialog closes the chat window instead of the dialog. The chat window's root element has a keydown handler that closes the window on `'escape'`, and cat
Original PR description
**Steps to Reproduce:** 1. Send a message to Marc demo with Mitchell admin or vice-versa, read the message from reciever's side. 2. Click on seen-by indicator from sender's side, make sure the dialog…
**Steps to Reproduce:** 1. Send a message to Marc demo with Mitchell admin or vice-versa, read the message from reciever's side. 2. Click on seen-by indicator from sender's side, make sure the dialog appears and then Press `'ESC'`. 3. Chat window closes whereas the dialog should have closed. Since #169737, pressing 'esc' on the seen-by dialog closes the chat window instead of the dialog. The chat window's root element has a keydown handler that closes the window on `'escape'`, and catches focus by default whenever something non-focusable is clicked inside it (e.g. the seen-by indicator). The seen-by dialog's content had no focusable element, so it never grabbed focus for itself, leaving focus on the chat window. Pressing 'escape' therefore closed the chat window instead of the dialog. This commit fixes the issue by adding tabindex on the template, letting the dialog grab focus like other dialogs/popovers already do, so `'escape'` is handled by the dialog first. task-4895004
On python 3.10.12 `test_export_translatable_resources` fails. This is fixed in this commit build-944659 I only tested it on 17.0 since we do not seem to have the build error on higher versions. But the minimum python version is 3.10 until [excluding saas-19.1](https://github.com/odoo/odoo/blob/11ee42b4bf70a1008b06d13a48263e42c381aeed/odoo/release.py#L39) Forward-Port-Of: odoo/odoo#280927
Original PR description
On python 3.10.12 `test_export_translatable_resources` fails. This is fixed in this commit build-944659 I only tested it on 17.0 since we do not seem to have the build error on higher versions. But the minimum python version is 3.10 until [excluding saas-19.1](https://github.com/odoo/odoo/blob/11ee42b4bf70a1008b06d13a48263e42c381aeed/odoo/release.py#L39) Forward-Port-Of: odoo/odoo#280927
When several xmlids point to the same record, PostgreSQL's UPDATE ... FROM can match multiple source rows to one target and pick an arbitrary value. Aggregate translations per res_id in import order so the later entry wins Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277818
Original PR description
When several xmlids point to the same record, PostgreSQL's UPDATE ... FROM can match multiple source rows to one target and pick an arbitrary value. Aggregate translations per res_id in import order so the later entry wins Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277818