Daily updates from Odoo
Tuesday, August 11, 2026
25 changes · 18.0
Resolved issues and error corrections
Fixed an issue in Documents where clicking inside the “Search More” selection dialog could unexpectedly close it while editing document details. Users can now sort, resize columns, and select contacts or related records without losing the dialog or their current document selection.
Original PR description
Steps to reproduce: 1. Install Documents 2. In the Documents list view, select a document to display the inspector. 3. Edit a field such as Owner or Customer which uses a Many2one widget. 4. In the…
Steps to reproduce: 1. Install Documents 2. In the Documents list view, select a document to display the inspector. 3. Edit a field such as Owner or Customer which uses a Many2one widget. 4. In the field dropdown, click "Search More..." to open a modal dialog. 5. Click inside the "Search More..." modal (e.g., to sort columns or resize headers). Issue: - The modal dialog immediately closes, and the contact cannot be selected. Root cause: - When an inspector field is edited, the record row is put into edit mode. While in edit mode, the documents list renderer listens for global clicks. Clicking inside the "Search More..." modal dialog targets elements that have `.o_list_renderer` (since the modal dialog renders a list view). Because the click target is within a list renderer but is not a document row, `DocumentsListRenderer.onGlobalClick` executes and clears the selection of the main list view. Clearing the selection unmounts the edited field in the inspector, thereby destroying the modal dialog stack. Solution: - Modify DocumentsListRenderer.onGlobalClick to scope click handling to the current Documents list renderer. Ignore clicks outside this.root.el, so interactions in nested UI such as Search More... do not clear the main selection and destroy the inspector field. opw-6253360 Forward-Port-Of: odoo/enterprise#119262
Belgian Acerta payroll exports now include weekend days when an eligible leave period, such as sick leave, overlaps a weekend. This helps ensure reports match Acerta requirements and avoids missing leave information in payroll submissions.
Original PR description
## Steps to reproduce: - Install l10n_be_hr_payroll_acerta - Create an employee in a belgian company - Create a sick time off for the created employee that overlaps with a weekend - Export acerta report for the employee - Notice the weekend that overlaps with the time off is not present in the report ## Cause: While exporting the report file we only loop over the created work entries' dates and since weekends doesn't have work entries we don't consider them in the report. ## Fix: When generating the line of a leave's start date we check if the leave overlaps with a WE, we fetch the WE's date and we generate a line for each day of the WE. According to Acerta this is the correct behavior for their reports for specific types of leaves. **opw-6313534**
Odoo now recognizes five new response codes introduced by Chile's tax authority for supplier electronic documents. This prevents affected documents from getting stuck during processing and keeps the workflow aligned with the latest SII requirements.
Original PR description
**Before this PR:** After the implementation of Resolution 161 of November 13th 2025, SII responses included keys not supported by the current l10n_cl_edi implementation. This resulted in supplier DTEs not being processed as they were before the change, because the five new keys were not found in Odoo's current `l10n_cl_claim` field, causing that the documents with these responses, were kept in a loop not solved. **After this PR:** The five new values from the resolution, along with their translations, were added to the selector field, fixing the process flow. **SII Reference:** https://www.sii.cl/normativa_legislacion/resoluciones/2025/reso161.pdf (see Event Code, page 5) Forward-Port-Of: odoo/enterprise#121833
This fix prevents a system error when an Australian Single Touch Payroll submission is attempted without any payslips or employees. Instead, users receive a clear validation message so they can correct the missing payroll data before submitting to the ATO.
Original PR description
When submitting payroll data to the ATO from an STP record without any payslips or employees, a traceback is raised. Steps to reproduce the error: - Install ``l10n_au_hr_payroll_account`` module -…
When submitting payroll data to the ATO from an STP record without any payslips or employees, a traceback is raised. Steps to reproduce the error: - Install ``l10n_au_hr_payroll_account`` module - Switch to ``My australian Company`` - Go to Payroll > Configuration > Settings > In Australian Localization, Set BMS ID > Set STP Responsible and his date of birth - Go to Payroll > Reporting > Single Touch Payroll > Create a new record > Set Payment Date > Submit to ATO > Sign & Submit to ATO Traceback: ```py IndexError: tuple index out of range ``` https://github.com/odoo/enterprise/blob/b0e48baaf99bdc4faefd2ffdd3bd5637fb548593/l10n_au_hr_payroll_account/models/l10n_au_stp.py#L228-L233 The traceback occurs because ``_get_fiscal_year_start()`` assumes that the STP record always contains at least one payslip or one employee. When these recordsets are empty, indexing the first element raises an IndexError. Solution: This commit validates that the required payslips or employees are present before the submission and raises a validation error instead of a traceback.
The French VAT reimbursement declaration now includes the bank account holder's name, which is required for form 3519. This helps businesses submit complete declarations and reduces the risk of rejection or follow-up requests.
Original PR description
For reimbursement declarations, the name of the holder of the account is required This commits adds holder's name to the account data zone no-task-id
This fix ensures Mexican electronic payment documents use the required six-decimal precision for tax amounts. It prevents valid customer payments from being rejected due to small rounding mismatches in CFDI validation.
Original PR description
**Steps to reproduce:** - Checkout the source code before this commit: https://github.com/odoo/enterprise/commit/57e999b6a0d0639a09ee3518045669b3258eeb8f - Install Accounting and l10n_mx_edi -…
**Steps to reproduce:** - Checkout the source code before this commit: https://github.com/odoo/enterprise/commit/57e999b6a0d0639a09ee3518045669b3258eeb8f - Install Accounting and l10n_mx_edi - Checkout the source code after the commit - Switch to a Mexican company (e.g. ESCUELA KEMPER URGATE) - Make sure that "Outstanding Receipts accounts" are set on the Bank journal - Create an invoice: * Customer: [any] (e.g. Acme Corporationà * Payment Way: Efectivo * Payment Terms: [10 Days after End of Next Month] (in order to set "Payment Policy" to "PPD") * Product: [any] * Quantity: 1.0 * Price: 295.17 * Taxes: 16% - Confirm the invoice - Send CFDI - Register payment - "Upate Payments" from the invoice **Issue:** The payment CFDI is in error: `Code : CRP20274 Message : El campo ImporteP que corresponde a Traslado, no es igual a la suma de los importes de los impuestos registrados en el documento relacionado donde el impuesto del documento relacionado sea igual al campo ImpuestoP de este elemento y la TasaOCuotaP del documento relacionado sea igual al campo TasaOCuotaP de este elemento.` **Cause:** This commit https://github.com/odoo/enterprise/commit/57e999b6a0d0639a09ee3518045669b3258eeb8f introduces 6 decimals for the payment CFDI taxes. However, if `l10n_mx_edi` module is not upgraded, the required changes in `l10n_mx_edi.payment20` template won't be applied and the amounts will not sum up correctly. opw-646062
The Dutch tax reporting status check now handles cases where a tax return record is missing its closing entry. This prevents one incomplete or broken record from stopping status updates for all other Digipoort tax returns.
Original PR description
The `l10n_nl_reports_sbr_status_info` contains the `l10n_nl_reports_sbr.status.service` class. The class is responsible for fetching the status of sent Digipoort tax returns. The status is then posted as a chatter message to the tax return's closing entry. Issues can arise when one of the status service records is, for whatever reason, missing a closing entry. In such case, the message cannot be posted, resulting in an exception being raised. Since the records are processed in a loop without a try-catch, this causes the whole action to fail. This can lead to one broken record effectively shutting down the whole module's functionality. This PR adds some if-else checks to gracefully handle the case where the closing entry is missing. Related tickets: opw-5901446 and opw-6410082 Forward-Port-Of: odoo/enterprise#125996
Since commit ff57c836438b1fec32527db39270b02c68504955 `website` fails to install. The cache reset should not be done when installing modules. Reproduce: 1. Create a new empty db 2. Set language to German 3. Install Website 4. The install gets stuck and you can't access the db anymore. task-None
Original PR description
Since commit ff57c836438b1fec32527db39270b02c68504955 `website` fails to install. The cache reset should not be done when installing modules. Reproduce: 1. Create a new empty db 2. Set language to German 3. Install Website 4. The install gets stuck and you can't access the db anymore. task-None
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-pr
Forward-Port-Of: odoo/odoo#281520Problem: When sending an invoice, deleting an attachment can lead to the deletion of another attachment with the same name. Steps to reproduce: 1. Duplicate the invoice PDF report 2. Edit the email template and add the duplicated report as a dynamic report attachment 3. Create an invoice, confirm it and send it by email 4. Delete one of the attachments in the email composer and send the email 5. Check the sent email and notice how the other attachment with the same name has been deleted
Original PR description
Problem: When sending an invoice, deleting an attachment can lead to the deletion of another attachment with the same name. Steps to reproduce: 1. Duplicate the invoice PDF report 2. Edit the email template and add the duplicated report as a dynamic report attachment 3. Create an invoice, confirm it and send it by email 4. Delete one of the attachments in the email composer and send the email 5. Check the sent email and notice how the other attachment with the same name has been deleted as well. Cause: The code was using the name of the attachment to identify it, but the name is not unique and this leads to attachments with the same name being deleted. opw-6413314
Issue: ------- After the fix: https://github.com/odoo/odoo/commit/f1557211d9e7f83761bb36e4800e4c2f62b234c5 we can't create a child menu for a mega menu or a menu can't be a mega menu when there's an existing child menu except the case of top level menu i.e; (url: /default-main-menu) and that menu will have no parent_id obviously... Now, as per the above pr conditions the top level can be set as mega menu since it has no parent id. And in version 17.3 in the pr https://github.com/odoo/odoo/
Original PR description
Issue: ------- After the fix: https://github.com/odoo/odoo/commit/f1557211d9e7f83761bb36e4800e4c2f62b234c5 we can't create a child menu for a mega menu or a menu can't be a mega menu when there's an…
Issue:
-------
After the fix:
https://github.com/odoo/odoo/commit/f1557211d9e7f83761bb36e4800e4c2f62b234c5 we can't create a child menu for a mega menu or a menu can't be a mega menu when there's an existing child menu except the case of top level menu i.e; (url: /default-main-menu) and that menu will have no parent_id obviously...
Now, as per the above pr conditions the top level can be set as mega menu since it has no parent id. And in version 17.3 in the pr https://github.com/odoo/odoo/commit/47af533e9f5f721b63570d3b301951f3855384a1 a 'Jobs' menu is being created and its parent_id refers to that top level menu which we have set as mega menu. And when the records gets validated during migration the database will get blocked.
Solution:
-----------
Restrict the user by throwing the same user error, when checking/selecting the top level menu as mega menu since it has existing child menus.
Step to reproduce:
-----------------------
1. Create a database in version 17.0 with 'website_hr_recruitment' installed.
2. Go to website menus, set a top level menu(/default-main-menu) as mega menu.
3. Migrate the database to version 18.0 or more.
Traceback:
```
File "/home/odoo/src/odoo/18.0/odoo/models.py", line 5297, in _create
records._validate_fields(name for data in data_list for name in data['stored'])
File "/home/odoo/src/odoo/18.0/odoo/models.py", line 1636, in _validate_fields
check(self)
File "/home/odoo/src/odoo/18.0/addons/website/models/website_menu.py", line 95, in _validate_parent_menu
raise UserError(_("A mega menu cannot have a parent or child menu."))
odoo.exceptions.UserError: A mega menu cannot have a parent or child menu.
File "/home/odoo/src/odoo/18.0/odoo/tools/convert.py", line 603, in _tag_root
raise ParseError('while parsing %s:%s, somewhere inside\n%s' % (
odoo.tools.convert.ParseError: while parsing /home/odoo/src/odoo/18.0/addons/website_hr_recruitment/data/config_data.xml:13, somewhere inside
<record id="website_menu_jobs" model="website.menu">
<field name="name">Jobs</field>
<field name="url">/jobs</field>
<field name="parent_id" ref="website.main_menu"/>
<field name="sequence">59</field>
</record>
```
Ref Images:
Before Fix:
<img width="1598" height="599" alt="image" src="https://github.com/user-attachments/assets/ef719945-a11b-4134-97f8-4b583c4ea6bc" />
After Fix:
<img width="1582" height="633" alt="image" src="https://github.com/user-attachments/assets/da326e45-0de8-4d42-ad47-845bfaedc84e" />
OPW - 6094298
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#263025Clearing the cache in the `write` of `ir.module` caused issues when installing `website`. Having it in `create` was enough for the original use case that prompted the PR. So we remove the `write` in this commit. Reproduce: 1. Create a new empty db 2. Set language to German 3. Install Website 4. The install gets stuck and you can't access the db anymore. task-None
Original PR description
Clearing the cache in the `write` of `ir.module` caused issues when installing `website`. Having it in `create` was enough for the original use case that prompted the PR. So we remove the `write` in this commit. Reproduce: 1. Create a new empty db 2. Set language to German 3. Install Website 4. The install gets stuck and you can't access the db anymore. task-None
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 Forward-Port-Of: odoo/odoo#276648
During the backport we discovered a programming error in `_get_peppol_document_params`. The super function can return `None` values for both `edi_user` and `document`. This can lead to a traceback when the variables are used. We do not have any known issues in 18.0 or higher versions. (Probably because the move send was heavily refactored.) But better safe than sorry. It could maybe happen with the batch sending or in case the "surrounding" logic is refactored in the future. task-None
Original PR description
During the backport we discovered a programming error in `_get_peppol_document_params`. The super function can return `None` values for both `edi_user` and `document`. This can lead to a traceback when the variables are used. We do not have any known issues in 18.0 or higher versions. (Probably because the move send was heavily refactored.) But better safe than sorry. It could maybe happen with the batch sending or in case the "surrounding" logic is refactored in the future. task-None
The test employee uses Europe/Brussels, but only the 35h calendar had an explicit timezone. The 40h calendar still inherited its timezone from the environment, which could lead to different work entry durations depending on the test setup. This commit sets the 40h calendar timezone explicitly to Europe/Brussels as well, keeping both contract calendars consistent with the employee. [error-938862 ](https://runbot.odoo.com/odoo/error/938862) --- I confirm I have signed the CLA and read t
Original PR description
The test employee uses Europe/Brussels, but only the 35h calendar had an explicit timezone. The 40h calendar still inherited its timezone from the environment, which could lead to different work entry durations depending on the test setup. This commit sets the 40h calendar timezone explicitly to Europe/Brussels as well, keeping both contract calendars consistent with the employee. [error-938862 ](https://runbot.odoo.com/odoo/error/938862) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Steps to reproduce: - Open the first default To-do note. - Select the word Welcome. - Open the text color picker. - Click the trash icon to reset the text color. Issue: - When resetting the text color, the selected text also loses its font-size style. Cause: - The `color_plugin` removes the wrapper element after resetting the color style. If the same element also contains other inline styles (such as font-size), those styles are lost when the element is removed. Solution: - After
Original PR description
Steps to reproduce: - Open the first default To-do note. - Select the word Welcome. - Open the text color picker. - Click the trash icon to reset the text color. Issue: - When resetting the text color, the selected text also loses its font-size style. Cause: - The `color_plugin` removes the wrapper element after resetting the color style. If the same element also contains other inline styles (such as font-size), those styles are lost when the element is removed. Solution: - After resetting the color style, only remove the element if it no longer has any other inline styles. Otherwise, keep the element so that the remaining styles are preserved. task-6279198
Problem: When a `table` with a `color`/`backgroundColor` contains a nested `table`, `distributeTableColorsToAllCells` propagates the outer table's color to every `td` in the subtree, including cells belonging to the inner table. The inner table's own color is then discarded since its `td`s already have a value. Cause: `table.querySelectorAll("td")` returns every `td` in the entire subtree, not just the table's own direct cells. Solution: Scope the selected `td`s to `td.closest("table"
Original PR description
Problem:
When a `table` with a `color`/`backgroundColor` contains a nested `table`, `distributeTableColorsToAllCells` propagates the outer table's color to every `td` in the subtree, including cells belonging to the inner table. The inner table's own color is then discarded since its `td`s already have a value.
Cause:
`table.querySelectorAll("td")` returns every `td` in the entire subtree, not just the table's own direct cells.
Solution:
Scope the selected `td`s to `td.closest("table") === table`, so a table's color is only distributed to its own cells.
Steps to reproduce:
1. Add a `background-color` to an outer `table`.
2. Nest a `table` with a different `background-color` inside one of its cells.
3. Load/normalize the content in the editor.
4. Observe both tables' cells carry the outer table's color.
opw-6438972
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prThe SIRET value on the contact form should not be overwritten when registering with the PDP. This fix from 18.0 to 18.2 task-6442186
Original PR description
The SIRET value on the contact form should not be overwritten when registering with the PDP. This fix from 18.0 to 18.2 task-6442186
Currently there is a traceback on PDP / Peppol. `render_peppol_errors` expects `error` as a dictionary from which it extracts the message. But we extract the message already before passing it to `render_peppol_errors`. The issue was introduced in this commit 8b7c36e45552943a266d2973eda89b9cec8ae1a4 . It also breaks the PDP logging logic from commit 08eea0a0788ee2588726a35d693c338b4974ca1e . ``` Traceback (most recent call last): File "/home/odoo/src/odoo/odoo/http.py", line 25
Original PR description
Currently there is a traceback on PDP / Peppol. `render_peppol_errors` expects `error` as a dictionary from which it extracts the message. But we extract the message already before passing it to…
Currently there is a traceback on PDP / Peppol.
`render_peppol_errors` expects `error` as a dictionary from which it extracts the message.
But we extract the message already before passing it to `render_peppol_errors`.
The issue was introduced in this commit
8b7c36e45552943a266d2973eda89b9cec8ae1a4 .
It also breaks the PDP logging logic from commit
08eea0a0788ee2588726a35d693c338b4974ca1e .
```
Traceback (most recent call last):
File "/home/odoo/src/odoo/odoo/http.py", line 2577, in __call__
response = request._serve_db()
^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/odoo/http.py", line 2104, in _serve_db
return self._transactioning(
^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/odoo/http.py", line 2167, in _transactioning
return service_model.retrying(func, env=self.env)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/odoo/service/model.py", line 157, in retrying
result = func()
^^^^^^
File "/home/odoo/src/odoo/odoo/http.py", line 2134, in _serve_ir_http
response = self.dispatcher.dispatch(rule.endpoint, args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/odoo/http.py", line 2382, in dispatch
result = self.request.registry['ir.http']._dispatch(endpoint)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/odoo/addons/base/models/ir_http.py", line 333, in _dispatch
result = endpoint(**request.params)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/odoo/http.py", line 754, in route_wrapper
result = endpoint(self, *args, **params_ok)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/addons/web/controllers/dataset.py", line 42, in call_button
action = call_kw(request.env[model], method, args, kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/odoo/api.py", line 535, in call_kw
result = getattr(recs, name)(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/addons/account_peppol/models/account_journal.py", line 34, in peppol_get_message_status
edi_users._peppol_get_message_status()
File "/home/odoo/src/odoo/addons/account_peppol/models/account_edi_proxy_user.py", line 352, in _peppol_get_message_status
processed_message_uuids = edi_user._peppol_process_messages_status(messages_to_process, uuid_to_record)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/addons/l10n_fr_pdp/models/account_edi_proxy_user.py", line 308, in _peppol_process_messages_status
processed_message_uuids += super()._peppol_process_messages_status(other_messages, uuid_to_record)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/addons/account_peppol_response/models/account_edi_proxy_user.py", line 212, in _peppol_process_messages_status
return processed_message_uuids + super()._peppol_process_messages_status(other_messages, uuid_to_record)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/addons/account_peppol/models/account_edi_proxy_user.py", line 385, in _peppol_process_messages_status
move._message_log(body=render_peppol_errors(move, error.get('data', {}).get('message') or error['message']))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/addons/account_peppol/tools/peppol_errors.py", line 81, in render_peppol_errors
raw_message = error.get('data', {}).get('message') or error['message']
^^^^^^^^^
AttributeError: 'str' object has no attribute 'get'
```
task-NoneVersion: -------- - 18.0 Steps to reproduce: ------------------- - Install `purchase` and `stock` - Create a storable product with Supplier info - Create a Replenishment Rule for the product - Click the information icon on the replenishment rule to open the replenishment information popup - Click **Set as Supplier** under **vendor tab** Issue: ------ The orderpoint is assigned the `Cross-Dock` route instead of the warehouse's `Buy` route. As a result, replenishments are conf
Original PR description
Version: -------- - 18.0 Steps to reproduce: ------------------- - Install `purchase` and `stock` - Create a storable product with Supplier info - Create a Replenishment Rule for the product - Click…
Version: -------- - 18.0 Steps to reproduce: ------------------- - Install `purchase` and `stock` - Create a storable product with Supplier info - Create a Replenishment Rule for the product - Click the information icon on the replenishment rule to open the replenishment information popup - Click **Set as Supplier** under **vendor tab** Issue: ------ The orderpoint is assigned the `Cross-Dock` route instead of the warehouse's `Buy` route. As a result, replenishments are configured to use the wrong route for vendor procurement. Cause: ------ Clicking **Set as Supplier** calls `SupplierInfo.action_set_supplier()`. When the orderpoint's current route does not contain a rule with `action='buy'`, the method falls back to assigning a route using: https://github.com/odoo/odoo/blob/788c2f3f19a3a2c70e2efcc683e21965c634b6de/addons/purchase_stock/models/product.py#L141-L142 This search is not restricted to the orderpoint's warehouse or to the warehouse's Buy route. It simply returns the first stock.rule whose action is buy, according to the default ordering of stock.rule. Prior to 18.0, this implementation was effectively safe because each warehouse only had a single stock.rule with action='buy': the warehouse's buy_pull_id. Therefore, the unscoped search always returned the correct Buy route. This changed in 18.0 with this [commit](https://github.com/odoo/odoo/commit/af5479dfdbed) As part of the new push-rule architecture, `StockWarehouse._get_receive_rules_dict()` now inserts an additional action='buy' rule into the Cross-Dock route: https://github.com/odoo/odoo/blob/788c2f3f19a3a2c70e2efcc683e21965c634b6de/addons/purchase_stock/models/stock.py#L84-L89 This rule is intentionally used to trigger the Cross-Dock push chain when `Buy` is the warehouse reception method. As a consequence, a warehouse now contains two different stock.rule records with action='buy': the warehouse's `Buy` rule (buy_pull_id); the Cross-Dock trigger rule. The unscoped search performed by `action_set_supplier()` therefore has two equally valid candidates and may return the Cross-Dock rule, depending on the default ordering of stock.rule. This results in the Cross-Dock route being assigned to the orderpoint instead of the warehouse's `Buy route`. The issue no longer reproduces from saas-18.2 onwards because the Cross-Dock route was removed in this [commit](https://github.com/odoo/odoo/commit/c2bf8b10d765) Fix: ---- Resolve the Buy route directly from the orderpoint's warehouse using `warehouse_id.buy_pull_id.route_id`, which explicitly represents the warehouse's Buy route generated by StockWarehouse._generate_global_route_rules_values(). Keep the previous unscoped search only as a fallback when the warehouse does not have a configured Buy rule. This ensures the supplier assignment always selects the warehouse's intended procurement route instead of another route that happens to contain a buy rule. --- opw-6365633 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
#### Issue When manually adding component lines in the subcontracting Record Production flow, extra stock move lines can remain in the database without a linked stock move. Those lines have no move_id, so their related state is empty. They can later be selected by stock reservation code and cause validation errors when processing the transfer. #### Steps to reproduce 1. Create a subcontracted product. 2. Confirm a subcontracting receipt/purchase flow for that product. 3. Open the s
Original PR description
#### Issue When manually adding component lines in the subcontracting Record Production flow, extra stock move lines can remain in the database without a linked stock move. Those lines have no…
#### Issue When manually adding component lines in the subcontracting Record Production flow, extra stock move lines can remain in the database without a linked stock move. Those lines have no move_id, so their related state is empty. They can later be selected by stock reservation code and cause validation errors when processing the transfer. #### Steps to reproduce 1. Create a subcontracted product. 2. Confirm a subcontracting receipt/purchase flow for that product. 3. Open the subcontracting Record Production popup. 4. Remove an existing component line. 5. Add a new component line for another storable product available at the subcontractor location. 6. Save/record the production. 7. Check stock.move.line records , Inventory > History > Group By Status. An extra stock move line is left with no move_id. #### Root cause The inverse of `mrp.production.move_line_raw_ids` already collects and deletes move lines detached from existing raw moves. However, when the user adds a new component product, the inverse creates a new additional raw move. Creating that raw move can also create reserved move lines. The inverse then replaces `move.move_line_ids` with the user-entered lines, but it did not collect the newly created reserved lines before replacing them. Those reserved lines were detached from the move and left in the database as orphan stock move lines. #### Fix Apply the same cleanup logic to newly created additional raw moves: collect their auto-created move lines before replacing `move_line_ids`, then unlink those detached lines at the end of the inverse. opw-6304649 --- 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 Forward-Port-Of: odoo/odoo#281276
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 Forward-Port-Of: odoo/odoo#281276
Miscellaneous changes
This reverts commit ff57c836438b1fec32527db39270b02c68504955. It causes issues when installing `website`. Reproduce: 1. Create a new empty db 2. Set language to German 3. Install Website 4. The install gets stuck and you can't access the db anymore. task-None
Original PR description
This reverts commit ff57c836438b1fec32527db39270b02c68504955. It causes issues when installing `website`. Reproduce: 1. Create a new empty db 2. Set language to German 3. Install Website 4. The install gets stuck and you can't access the db anymore. task-None
- Compute the standard durations for all French leaves in a single `_get_durations()` call instead of recomputing them for each leave. - Reuse the precomputed duration mapping while calculating the French legal duration for each leave. - Keep the existing French-specific duration calculation unchanged, including public holidays, company calendar, date extension, and half-day handling. This avoids repeated ORM computations when processing multiple French leaves in a batch an
Original PR description
- Compute the standard durations for all French leaves in a single `_get_durations()` call instead of recomputing them for each leave. - Reuse the precomputed duration mapping while calculating the…
- Compute the standard durations for all French leaves in a single `_get_durations()` call instead of recomputing them for each leave. - Reuse the precomputed duration mapping while calculating the French legal duration for each leave. - Keep the existing French-specific duration calculation unchanged, including public holidays, company calendar, date extension, and half-day handling. This avoids repeated ORM computations when processing multiple French leaves in a batch and significantly improves the performance of leave duration computation. Performance testing was performed using the `hr.leave.employee.report` introduced in 19.1, which calls `_get_durations()` on a large batch of virtual leaves. Performance testing on a database containing 677 leaves, including 298 French leaves: | Metric | Before | After | |------------------------------------|-----------------|-------------| | Standard duration computations | 298 | 1 | | Total `_get_durations()` | >169s (timeout) | ~24s | not specific to the employee report and benefits any caller that invokes _get_durations() on a larger batch. **opw-6421323** --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Behavior before: When uploading an animated GIF to fields utilizing image responsive sizing or cropping (such as employee avatars or product images), no downscaling or cropping occurs for sub-variants like 'image_128' or 'image_1024'. The responsive fields replicate the exact file size and data footprint of the original large image, leading to heavy storage overhead and unnecessary frontend asset loading. Behavior after: Animated GIF images scale down and crop correctly to match requested r
Original PR description
Behavior before: When uploading an animated GIF to fields utilizing image responsive sizing or cropping (such as employee avatars or product images), no downscaling or cropping occurs for…
Behavior before: When uploading an animated GIF to fields utilizing image responsive sizing or cropping (such as employee avatars or product images), no downscaling or cropping occurs for sub-variants like 'image_128' or 'image_1024'. The responsive fields replicate the exact file size and data footprint of the original large image, leading to heavy storage overhead and unnecessary frontend asset loading. Behavior after: Animated GIF images scale down and crop correctly to match requested responsive dimensions and aspect ratios. Sub-variants take up significantly less space in the filestore, matching proportional dimensions without dropping or stripping the underlying animation loop. Large images that are smaller than requested boxes are safely left un-upscaled to maximize database deduplication. Root Cause: Historically, a legacy safeguard bypassed GIF resizing and cropping because older versions of the Pillow library did not gracefully handle multi-frame sequential image buffers. As a result, standard 'image.crop()', 'image.thumbnail()', or 'image.resize()' implementations would flatten multi-frame animated sequences down into a single, static first frame or throw dimension/mode mismatches during save operations. Fix: Intercept the image processing pipeline when encountering an asset identified as a GIF where 'is_animated' evaluates to True. Implemented a unified, in-place multi-frame helper routine (`_apply_gif_operation`) using PIL's 'ImageSequence.Iterator' to cleanly step through, normalize to a uniform color mode (RGBA), duplicate, and modify each animation frame individually. This single helper handles sequential workflows for both 'crop' and 'thumbnail' operations while preserving individual frame duration arrays and native loop metadata. Both 'resize' and 'crop_resize' leverage this logic to achieve precise dimensions cleanly. Crucially, upscaling (expanding) is intentionally unsupported for animated GIFs. Forcing a low-resolution, 256-color indexed animation to stretch beyond its native dimensions forces heavy color dithering across every single frame. This breaks the sequential LZW pattern compression, causing the resulting file sizes to skyrocket catastrophically. The logic utilizes thumbnail boundaries to completely block this expansion, protecting the filestore from accidental bloat. Benchmark: -------------------------------------------------------------------------------------------- | GIF size | Variant | Size Before (KB) | Size After (KB) | |---------------|--------------------|--------------------------|-----------------------| | (2.5MB) | image_1024 | 2475.87 | 2475.87 | | | image_128 | 2475.87 | 257.93 | |---------------|--------------------|--------------------------|-----------------------| | (3.8MB) | image_1024 | 3724.93 | 3724.93 | | | image_128 | 3724.93 | 463.62 | |----------------|-------------------|--------------------------|-----------------------| | (442KB) | image_1024 | 432.49 | 432.49 | | | image_128 | 432.49 | 36.14 | |----------------|-------------------|--------------------------|-----------------------| | (3.6MB) | image_1024 | 3491.98 | 3491.98 | | | image_128 | 3491.98 | 1728.25 | |----------------|-------------------|--------------------------|-----------------------| opw-6232841 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