Monday, August 10, 2026
10 changes · 17.0
Resolved issues and error corrections
The selection options for l10n_id_coretax_add_info_07/08 and l10n_id_coretax_facility_info_07 were swapped: the "additional information" fields showed facility stamp text and vice versa. Also add the UoM codes and new kode faktur 07 additional info/facility stamp options published by DJP on 2026-01-26. task-6434742
Original PR description
The selection options for l10n_id_coretax_add_info_07/08 and l10n_id_coretax_facility_info_07 were swapped: the "additional information" fields showed facility stamp text and vice versa. Also add the UoM codes and new kode faktur 07 additional info/facility stamp options published by DJP on 2026-01-26. task-6434742
Steps to Reproduce the Error (Odoo SaaS 19.2): 1. Install l10n_gcc_invoice localization & Accounting 2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings > Configuration > Customer Invoices > Default Terms and Conditions 3. Create invoice with ar_001 partner 4. Confirm the invoice 5. Try to create credit note → Error: KeyError: 'en_US' Root Cause: The _load_narration_translation() workaround reads raw invoice_terms from DB and injects the entire JSONB di
Original PR description
Steps to Reproduce the Error (Odoo SaaS 19.2): 1. Install l10n_gcc_invoice localization & Accounting 2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings >…
Steps to Reproduce the Error (Odoo SaaS 19.2):
1. Install l10n_gcc_invoice localization & Accounting
2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings > Configuration > Customer Invoices > Default Terms and Conditions
3. Create invoice with ar_001 partner
4. Confirm the invoice
5. Try to create credit note → Error: KeyError: 'en_US'
Root Cause:
The _load_narration_translation() workaround reads raw invoice_terms from DB and injects the entire JSONB dict directly into cache, bypassing ORM field conversion. When Odoo 19.2's improved ORM conversion runs, it creates nested JSON in narration instead of a flat structure.
Timeline:
- bedf1cb66fbb: Workaround added to prevent T&C duplication in preview
- 75f050b9650d: Root cause fixed in report template (conditional display) → Made _load_narration_translation() redundant
- 4e4156536bc9: Odoo 19.2 improved ORM conversion → Now conflicts with the redundant workaround, causing nested JSON
How It Breaks:
1. Invoice creation: _load_narration_translation() injects raw dict into cache
2. ORM writes: nested JSON stored: {ar_001: {en_US: ., ar_001: Arabic}}
3. Credit note creation: copy_translations() expects flat structure → Crashes: KeyError: 'en_US'
Why It's Safe to Remove:
Report template already prevents T&C duplication (commit 75f050b9650d). Removing the workaround restores proper credit note creation without breaking T&C display.
Changes:
- Remove moves._load_narration_translation() in create()
- Remove out self.filtered('id')._load_narration_translation() in _compute_narration()
opw : 6284943
Forward-Port-Of: odoo/odoo#271037#### Description of the issue: Activity filters using context_today() bucket against the UTC date instead of the user's local date, off by one for part of the day. Partial revert of #265250 (e048bb5), scoped to PyDate: UTC getters are right for PyDateTime, wrong for a calendar day. #### Current behavior before PR: A Perth (UTC+8) user finds an activity due today under "Future Activities" from 00:00 to 08:00 local, while the chatter labels the same activity "Today". #### Desired behavior
Original PR description
#### Description of the issue: Activity filters using context_today() bucket against the UTC date instead of the user's local date, off by one for part of the day. Partial revert of #265250 (e048bb5), scoped to PyDate: UTC getters are right for PyDateTime, wrong for a calendar day. #### Current behavior before PR: A Perth (UTC+8) user finds an activity due today under "Future Activities" from 00:00 to 08:00 local, while the chatter labels the same activity "Today". #### Desired behavior after PR is merged: context_today(), today and current_date return the user's local calendar day, so filters agree with the chatter. PyDateTime and PyTime keep the UTC getters; now and time.strftime() are unchanged. opw-6415985 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
An old refactor left some data around that are in conflict with other records for the same model. 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
Original PR description
An old refactor left some data around that are in conflict with other records for the same model. 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
The right value often comes from the user and the search implementation may not handle 'any' properly, however 'in' is nearly always implemented. For most cases, transform 'any' into a 'in' before calling Field.search. task-6446206 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
The right value often comes from the user and the search implementation may not handle 'any' properly, however 'in' is nearly always implemented. For most cases, transform 'any' into a 'in' before calling Field.search. task-6446206 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
l10n_fr_pdp's settings view inherits account_peppol and uses peppol_use_parent_company in `invisible`s. The node for that field is provided by account_peppol, but it was only added to account_peppol settings view in 0ab1e0323894. On a database whose account_peppol was not updated after this commit, installing l10n_fr_pdp does not upgrade account_peppol, so this invisible references a field that doesn't exist in the view, so tb at install ``` Error while validating view near: <form string=
Original PR description
l10n_fr_pdp's settings view inherits account_peppol and uses peppol_use_parent_company in `invisible`s. The node for that field is provided by account_peppol, but it was only added to account_peppol…
l10n_fr_pdp's settings view inherits account_peppol and uses peppol_use_parent_company in `invisible`s. The node for that field is provided by account_peppol, but it was only added to account_peppol settings view in 0ab1e0323894. On a database whose account_peppol was not updated after this commit, installing l10n_fr_pdp does not upgrade account_peppol, so this invisible references a field that doesn't exist in the view, so tb at install
```
Error while validating view near:
<form string="Settings" class="oe_form_configuration" js_class="base_settings">
<field name="is_root_company" invisible="1"/>
<app data-string="General Settings" string="General Settings" name="general_settings" logo="/base/static/description/settings.png">
Field 'peppol_use_parent_company' used in modifier 'invisible' (peppol_use_parent_company or account_peppol_proxy_state not in ('sender', 'pending', 'active')) must be present in view but is missing.
View error context:
{'file': '/home/odoo/src/odoo/17.0/addons/l10n_fr_pdp/views/res_config_settings_views.xml',
'line': 1,
'name': 'res.config.settings.view.form.inherit.proxy.user',
'view': ir.ui.view(2640,),
'view.model': 'res.config.settings',
'view.parent': ir.ui.view(1604,),
'xmlid': 'res_config_settings_view_form'}
```
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-prWe still have cases of people being confused by the fact that they send their invoices, reset it to draft, change something, then re-sending. Of course, the re-sending does not send on peppol, as it's already sent. It's more confusing than anything else. Prevent it if they're sent and not in error. task-6459869 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
We still have cases of people being confused by the fact that they send their invoices, reset it to draft, change something, then re-sending. Of course, the re-sending does not send on peppol, as it's already sent. It's more confusing than anything else. Prevent it if they're sent and not in error. task-6459869 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Description of the issue/feature this PR addresses: Odoo supports WebP image fields, but `base_import` validates remote images with `PIL.Image.open()`. Odoo intentionally leaves Pillow's WebP decoder unloaded, so a valid WebP URL is rejected as an unidentified image. Current behavior before PR: Importing a valid WebP image URL fails with `cannot identify image file`. Oversized and unsupported WebP files are also rejected by Pillow before the import-specific size policy can be applied. Desire
Original PR description
Description of the issue/feature this PR addresses: Odoo supports WebP image fields, but `base_import` validates remote images with `PIL.Image.open()`. Odoo intentionally leaves Pillow's WebP decoder unloaded, so a valid WebP URL is rejected as an unidentified image. Current behavior before PR: Importing a valid WebP image URL fails with `cannot identify image file`. Oversized and unsupported WebP files are also rejected by Pillow before the import-specific size policy can be applied. Desired behavior after PR is merged: Use Odoo's existing WebP header parser for dimension validation. Valid WebP URLs import unchanged, unsupported WebP remains rejected, and the existing 42-million-pixel import limit remains enforced. Tests cover valid, unsupported, and oversized WebP URL payloads. The complete `test_base_import` suite passes (56 tests, 0 failures/errors). --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Documentation and clarification updates
Description of the issue/feature this PR addresses: Signing the Odoo Individual Contributor License Agreement v1.0. Name: Alejandro Martínez GitHub login: alexmbar Email: alexmbar891@gmail.com Country: México Current behavior before PR: I have no CLA signature on file, so my pending l10n_mx contributions (#264576, #264580, #264582, #264583) fail the legal/cla check and cannot be merged. Desired behavior after PR is merged: doc/cla/individual/alexmbar.md is present and the legal/
Original PR description
Description of the issue/feature this PR addresses: Signing the Odoo Individual Contributor License Agreement v1.0. Name: Alejandro Martínez GitHub login: alexmbar Email: alexmbar891@gmail.com Country: México Current behavior before PR: I have no CLA signature on file, so my pending l10n_mx contributions (#264576, #264580, #264582, #264583) fail the legal/cla check and cannot be merged. Desired behavior after PR is merged: doc/cla/individual/alexmbar.md is present and the legal/cla check passes for my contributions. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Miscellaneous changes
**Problem** Opening a location applies the default filter `qty_available > 0 | virtual_available < 0`. Both fields are computed and non-stored, so each leaf goes through `_search_product_quantity`, which ran `search([])` and evaluated the operator in Python over the whole catalog: - `_compute_quantities_dict` `_read_group`s quants **and** incoming/outgoing moves, even when the searched field only needs quants, each scoped with `product_id IN (all_ids)`. - `_compute_quantities` th
Original PR description
**Problem** Opening a location applies the default filter `qty_available > 0 | virtual_available < 0`. Both fields are computed and non-stored, so each leaf goes through `_search_product_quantity`,…
**Problem**
Opening a location applies the default filter `qty_available > 0 | virtual_available < 0`.
Both fields are computed and non-stored, so each leaf goes through
`_search_product_quantity`, which ran `search([])` and evaluated the operator in
Python over the whole catalog:
- `_compute_quantities_dict` `_read_group`s quants **and** incoming/outgoing moves,
even when the searched field only needs quants, each scoped with
`product_id IN (all_ids)`.
- `_compute_quantities` then materialises every product through the ORM: it zeroes
five fields on each one and loops calling `.update` per product.
- `filtered_domain` iterates the full recordset to evaluate the operator.
Nothing is queried per record, but every step scales with the *total* number of
products, so runtime and (batched prefetch) queries grow with the catalog instead of
with the number of products that actually have stock.
**Solution**
Aggregate the underlying quants/moves once and evaluate the operator per product on
plain dicts:
- Only query what the field needs (`need_quant`/`need_in`/`need_out`); a search on
`qty_available` no longer touches moves.
- No `product_id IN (...)`: the `GROUP BY` only returns products that actually have
quants/moves, bounding the work by stock rather than by catalog size.
- Products with neither quant nor move have an implicit value of 0 and are never
loaded: when 0 satisfies the operator the result is returned as
`id not in <aggregated products that failed>`, otherwise as `id in <matches>`.
- `_compute_quantities` is never called, so no full-catalog ORM materialisation.
The context keys that scope or time-shift the quantity (`lot_id`, `owner_id`,
`package_id`, `from_date`, `to_date`) are applied to the aggregation domains exactly
as `_compute_quantities_dict` does. Like that method's raw aggregates, per-UoM
rounding is ignored, and — as the search already did — kit BoMs are not expanded.
Pre-fix:
| Unique products in location | Search Domain | (Moves=Quants) / Product | Run time | Queries |
|---|---|---|---|---|
| 1,000 | [("virtual_available", ">", 0)] | 1 | 0.15 Seconds | 125 |
| 10,000 | [("virtual_available", ">", 0)] | 1 | 1 Second | 420 |
| 100,000 | [("virtual_available", ">", 0)] | 1 | 10.6 Seconds | 3,400 |
| 100,000 | [("virtual_available", ">", 0)] | 10 | 12.0 Seconds | 3,550 |
| 100,000 | [("virtual_available", ">", 0)] | 50 | 14.5 | 3,700 |
| 500,000 | [("virtual_available", ">", 0)] | 1 | 60.4 Seconds | 17,000 |
| 500,000 | [("incoming_qty", ">", 0)] | 1 | 60.5 Seconds | 17,000 |
| 500,000 | ['or', ("incoming_qty", ">", 0), ("virtual_available", ">", 0)] | 1 | 63 Seconds | 17,170 |
Post-fix:
| Unique products in location | Search Domain | (Moves=Quants) / Product | Run time | Queries |
|---|---|---|---|---|
| 1,000 | [("virtual_available", ">", 0)] | 1 | 0.07 Seconds | 100 |
| 10,000 | [("virtual_available", ">", 0)] | 1 | 0.3 Seconds | 110 |
| 100,000 | [("virtual_available", ">", 0)] | 1 | 2.5 Seconds | 150 |
| 100,000 | [("virtual_available", ">", 0)] | 10 | 3.5 Seconds | 150 |
| 100,000 | [("virtual_available", ">", 0)] | 50 | 4.9 Seconds | 150 |
| 500,000 | [("virtual_available", ">", 0)] | 1 | 6.8 Seconds | 250 |
| 500,000 | [("incoming_qty", ">", 0)] | 1 | 3.2 Seconds | 130 |
| 500,000 | ['or', ("incoming_qty", ">", 0), ("virtual_available", ">", 0)] | 1 | 10.3 Seconds | 315 |
opw-6379459