Daily updates from Odoo
Thursday, July 2, 2026
318 changes
19 changes
Enhancements to existing features
This change removes technical e-reporting fields from the main invoice screen to reduce clutter for regular users. Important e-reporting status updates and blocking issues are still recorded in the invoice chatter, with a direct link to the related flow for easier follow-up.
Original PR description
E-reporting technical fields were displayed directly on invoices, adding noise for regular invoicing users. Hide the e-reporting status columns and technical block from the standard invoice views. Log the relevant e-reporting flow, status and blocking errors in the invoice chatter instead, with a link to the related flow. Also avoid reporting address validation errors on B2C invoices, as they are not required for Flux 10 e-reporting. Task-6273226 Forward-Port-Of: odoo/odoo#271865
Resolved issues and error corrections
This change prevents an error that could appear when users open the Stock report after removing Manufacturing. It restores the stock report setup during uninstall so the report continues to open normally even when MRP is no longer installed.
Original PR description
Currently an error occurs when user opens stock report after uninstalling mrp. Steps to replicate: - Install mrp. - Uninstall mrp and open `Stock > Reporting > Stock`. Error: ``` ValueError: Invalid…
Currently an error occurs when user opens stock report after uninstalling mrp.
Steps to replicate:
- Install mrp.
- Uninstall mrp and open `Stock > Reporting > Stock`.
Error:
```
ValueError: Invalid field product.product.is_kits in condition ('is_kits', '=', False)
```
Cause:
- The `mrp` module overrides the `stock.action_product_stock_view` window action domain with `is_kits` field referenced inside [1].
- When mrp is uninstalled, the `is_kits` field is removed from `product.product` but the overridden action domain remains stored in the database. Opening the action then tries to evaluate a domain referencing a non-existent field, resulting in this error.
Solution:
- Restore the original `stock.action_product_stock_view` domain during mrp uninstallation to remove the `is_kits` condition.
[1]: https://github.com/odoo/odoo/blob/c8390638cae4b4dafb805bc0d3a4149fb5194934/addons/mrp/views/product_views.xml#L164-L166
sentry-7332688253
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#269512This change prevents an access error that could block delivery validation when the delivery is linked to a sales order owned by another salesperson. It ensures the system can check the needed subscription information without exposing other sales data, so warehouse operations continue smoothly.
Original PR description
## **Issue:** When validating a delivery, users with Sales: Own Documents Only and Inventory Administrator access rights can encounter an access error if the delivery belongs to a sale order owned by…
## **Issue:** When validating a delivery, users with Sales: Own Documents Only and Inventory Administrator access rights can encounter an access error if the delivery belongs to a sale order owned by another salesperson. ## **Steps to reproduce:** - Install sale_subscription_stock. - Create a user with Sales: Own Documents Only and Inventory Administrator access rights. - Create a sale order as another user. - Validate the delivery with the restricted user. ## **Solution:** During _action_done(), [This line](https://github.com/odoo/enterprise/blob/19.0/sale_subscription_stock/models/stock_picking.py#L45) is checking subscription_state. Since the user does not have read access to the sale order, reading this field raises an access error and prevents the delivery from being validated. As the method only needs to read the subscription state, access the field with sudo() to avoid the unnecessary access error while preserving the existing business logic. Runbot Video : [Video](https://drive.google.com/file/d/1d7U2jTCxaaVk2YJcy3bi2SlYuT-yXMsu/view?usp=drive_link) OPW - 6295712 Forward-Port-Of: odoo/enterprise#122420
When a new file is uploaded in Documents, its available actions are now shown immediately. This fixes the previous behavior where users had to click away and reselect the file before the actions became visible.
Original PR description
Bug === When uploading a new file in documents, it's selected, but the actions are not visible (we need to unselect - select the record to see the actions). Task-5408471 Forward-Port-Of: odoo/enterprise#122396 Forward-Port-Of: odoo/enterprise#114770
This change updates HTML validation so an empty string is treated as valid content. It prevents empty knowledge articles and similar pages from being misread as broken HTML, which avoids display issues and failing tests.
Original PR description
The [related PR] introduced this santization check for invalid html in xml templates. However, it considers commits on empty knowledge articles as invalid HTML, causing an empty code view to be rendered which breaks some tests. Instead, we should consider an empty string as valid HTML. Related PR: https://github.com/odoo/odoo/pull/260405 Backport Of: https://github.com/odoo/odoo/pull/271882 runbot-937767
This fix makes the “Change Layout” dialog close as soon as a call ends. It prevents users from interacting with an outdated dialog and avoids errors if the call was already removed in the background.
Original PR description
Opening "Change Layout" during a call adds a dialog via the dialog service. When the call was removed by the server (e.g. the `discuss.channel.rtc.session/ended` notification tears down the call and runs `endCall()`), the dialog stayed open. Clicking any option then ran `onSelectLayout`, which operates on the now-gone call (`channel.setAsDiscussThread()`, `rtc.enterFullscreen()`), and crashed. The action's `isSelfInCall` condition only gates opening a new dialog, never dismisses one already up. Close the dialog reactively when the user is no longer in the call, using Owl's reactive effect on `channel.isSelfInCall`, the same way `MessageReactionMenu` closes itself once its message loses all reactions. task-6352477 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This change fixes an occasional issue where a task history window could open before the page had finished loading its data. As a result, users should no longer see random failures when using this flow, making the experience more reliable.
Original PR description
Sometimes the tour runner is trying to open the history dialog before Owl have received and updated the record data. This create an error, because the history dialog think there's no data to display. To avoid this issue, we add a step to ensure the Owl renderer has finished loading and populating the record data into the form view, before opening the history dialog. runbot-243510 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update ensures Ecuadorian payment methods get the correct SRI-related value when they are created. It fixes an issue where the field could be left unset, which helps keep payment configuration accurate and reliable.
Original PR description
Since bcfeed4b24f5155c111c3866e779bb2f119b9da8 the field used a default function relying on self.code, which is always falsy on creation. Make this field computed to correctly set the value.
This update prevents thin visual gaps from appearing in Chrome while users browse theme previews in the website configurator. It improves the appearance of the preview cards so the setup flow looks cleaner and more polished.
Original PR description
Steps to reproduce: - Open the website configurator in Chrome. - Choose an industry and reach the Layout step. - Look at the theme preview cards. => Thin gaps can appear between adjacent sections.…
Steps to reproduce: - Open the website configurator in Chrome. - Choose an industry and reach the Layout step. - Look at the theme preview cards. => Thin gaps can appear between adjacent sections. Before this commit, Chrome could show 1px gaps in configurator theme previews when the `iframe` was scaled down. This came from a known rendering issue with fractional transforms [1]. A similar issue was already fixed for website pages built with the Website Builder when using background shapes [2]. That fix uses JS to adjust each `.o_we_shape` size. In the configurator, previews are static and small, so a local CSS overlap is enough and avoids running layout calculations for each preview `iframe`. After this commit, configurator previews add a small overlap on sections and shapes, so Chrome no longer exposes the background seam. [1]: https://issues.chromium.org/issues/41137778 [2]: https://github.com/odoo/odoo/commit/f7fd40d619d8bc2b5edc09de3a71a1954b4f3b52 task-6340483 BEFORE THE FIX (only Chrome) <img width="706" height="544" alt="image" src="https://github.com/user-attachments/assets/93c94961-8fd3-43da-bf32-3932ee98118d" /> AFTER THE FIX (only Chrome) <img width="704" height="540" alt="image" src="https://github.com/user-attachments/assets/acfc474e-fa03-4ff5-8ab1-52070619d78f" />
This update fixes two issues in expense handling. Employees can now submit an expense even when they do not have a manager assigned, and they can continue adding comments or attachments on their own submitted expenses when questions or extra proof are needed.
Original PR description
# [FIX] hr_expense: Submitting an expense without a manager doesn't work If a user tries to submit an expense without having a manager, this will fail with "You are neither a Manager nor a HR Officer". To fix this, we are not going to check when the manager is the user that expense is linked to. --------- # [FIX] hr_expense: Employee cant use chatter on his own expenses An employee that created his expense was only able to add attachments and post message in the chatter when the expense was in draft. After this, it will still be able to attach attachment and post message without having the right to edit the expense. This is better as the employee will be able to answer questions that have been asked or add more proof if required. [task-4966942](https://www.odoo.com/odoo/all-tasks/4966942) Forward-Port-Of: odoo/odoo#273183 Forward-Port-Of: odoo/odoo#224575
This fix prevents the system from crashing when it encounters a session entry that does not include a trusted flag. It matters because some existing sessions can be missing this information, and the update makes those sessions continue to work normally instead of failing.
Original PR description
Some devices may not have a `trusted` key in their entry. This is the case for sessions created between these two commits: - https://github.com/odoo/odoo/commit/b6c2aafae2112ef98edca8a7f027716d9c15be11 - https://github.com/odoo/odoo/commit/61f22175ef3df37087887e7419dac54a620bbd55 Task-6348650 Forward-Port-Of: odoo/odoo#273062
This update prevents the editor’s command menu from opening when an emoji shortcut is used, avoiding unexpected popups while typing. It also makes emoji shortcuts work more reliably within a paragraph, improving the typing experience for users.
Original PR description
#### Description of the issue this PR addresses: - When an emoji shortcut ending with `/` (e.g. `:/` for 😕) is typed, the emoji plugin replaces the characters before the powerbox `on_input_handler`…
#### Description of the issue this PR addresses: - When an emoji shortcut ending with `/` (e.g. `:/` for 😕) is typed, the emoji plugin replaces the characters before the powerbox `on_input_handler` runs. Since `ev.data` still reflects the original typed `/`, the powerbox was incorrectly opening. - Emoji shortcuts works only when it is used at the end of a text node, because the matching logic checked the whole remaining substring from the current position. - Sometimes, pressing Backspace splits one text node into two, and then an emoji shortcut works at the end of the first text node even when the paragraph is visible as a single line. #### Desired behavior after PR is merged: - Check the DOM character at cursor position instead of `ev.data` to determine whether `/` is actually present before opening the powerbox. - Emoji shortcuts now works when used with a preceding space anywhere in the paragraph. Enterprise PR-https://github.com/odoo/enterprise/pull/118310 task-6243724 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#266284
Invoices sent through Viettel S-Invoice could fail when the returned ZIP file was structured differently than expected. This update makes Odoo correctly find the XML in both simple and nested ZIP packages, preventing errors and allowing invoice processing to complete normally.
Original PR description
Description of the issue/feature this PR addresses: The actual XML extraction hardcoded the double-zipped case by reading only the first entry of the outer zip (`zip_file.infolist()[0]`), assuming it…
Description of the issue/feature this PR addresses: The actual XML extraction hardcoded the double-zipped case by reading only the first entry of the outer zip (`zip_file.infolist()[0]`), assuming it was always a nested zip containing the XML. This made it fail when: - The XML was directly in the outer zip (single-zipped). - The zip contained multiple files and the first nested zip didn't hold the XML. Current behavior before PR: After sending an Invoice to Viettel S-Invoice, the e-Invoicing platform would return a ZIP containing one XML file. The XML File being double-unzipped, a traceback is raised. Desired behavior after PR is merged: The fix rewrites _recursive_zip_xml_file_data to actually be recursive. Invoices can be sent to Viettel S-Invoice without raising a traceback. opw-[6249929](https://www.odoo.com/odoo/project.task/6249929?debug=1) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#272643 Forward-Port-Of: odoo/odoo#268482
This update corrects how two guided features simulate user actions, so they now behave more like a real user. As a result, Knowledge tours and Studio interactions work reliably again and no longer fail because of missing or incorrectly handled input steps.
Original PR description
#### Description of the issue: - Since the search powerbox plugin now checks for the actual existence of `/` in the DOM, some knowledge tours were failing because only the input event was dispatched without inserting `/`. - In web_studio, `insertText` was not positioning the selection correctly after insertion and was not dispatching beforeinput event before the DOM insertion. #### After this commit: - Adapt the `openPowerbox` utility in knowledge to insert `/` in the DOM before opening the powerbox. - Dispatch `beforeinput` before DOM insertion and `input` after it in web_studio, and move the selection after the inserted text. Community PR-https://github.com/odoo/odoo/pull/266284 task-6243724 Forward-Port-Of: odoo/enterprise#118310
This update improves the error shown when a Point of Sale database transaction fails. Instead of a generic message, users and support teams now see the real underlying error, making it easier to understand and troubleshoot issues.
Original PR description
Before this commit the error "Transaction could not be created" was thrown when the transaction could not be created. This commit changes the behavior to throw the actual error that caused the transaction creation to fail, providing more context for debugging. Forward-Port-Of: odoo/odoo#273116
The UNSPSC code for organic fertilizers and plant nutrients (10171500) is now available again in the product classification list. This ensures users can correctly categorize these products in Accounting settings without missing a valid code.
Original PR description
The code 10171500 - Organic fertilizers and plant nutrients wasn't appearing. In the file that has the unspsc product codes this one was set to False. Steps to reproduce: - Activate module product_unspsc. - Go to product > accounting. - Verify that this code is not listed. Ticket [link](https://www.odoo.com/odoo/project.task/4461974) opw-4461974 Forward-Port-Of: odoo/enterprise#121914
This change corrects how inventory closing entries are calculated when multiple companies are used. It ensures each company’s stock valuation is based only on its own data, preventing one company’s figures from being mixed into another’s accounting records.
Original PR description
**Steps to reproduce on a new db:** (bug also reproducable on runbot but the impact is less easy to compute because of influence of other existing companies) - create a new company as company 2 and…
**Steps to reproduce on a new db:** (bug also reproducable on runbot but the impact is less easy to compute because of influence of other existing companies) - create a new company as company 2 and use the existing default company as company 1. - create a warehouse for both company - for both comp, in settings for the 'fiscal localization' set Package : Generic Chart of account, if not already set (to have account journals). - for both comp, in settings for inventory valuation set 'periodic' and for periodic valuation set 'daily' From company 1 : - create a storable product with standard price method and set a cost of 30 - set an onhand quantity of 1 if you navigate to 'inventory valuation' you'll see that : - initial balance is 0 - ending stock is 30 - the variation lines have a balance of 30 - all of this is expected From company 2 : - change the cost of the product to 10 - set an onhand quantity of 1 if you navigate to 'inventory valuation' you'll see that : - initial balance is 0 - ending stock is 10 - the variation lines have a balance of 10 - all of this is expected From any company : - navigate to 'scheduled actions' and select the action 'Stock Account: Inventory Valuation Closing' - click on 'Run Manually' - navigate to 'inventory valuation' **Current behavior:** with company 1 selected : - the initial balance is now 30 - ending stock still 30 - no variation lines - the initial balance was correctly increased by the closing entry with company 2 selected: - the initial balance is now 40 - the ending stock is still 10 - the variation lines credit 30 in stock valuation In company 2 the closing entry debitted 40 in stock valuation instead of 10 which increased the initial balance to 40 instead of 10 If you open the journal items you'll find the closing amls have a balance of 40 instead of 10 **Cause of the issue:** The _cron_post_stock_valuation() method calls action_close_stock_valuation() on both companies https://github.com/odoo/odoo/blob/bfa39854e56da4bf23295d62f63d66973ad0d78e/addons/stock_account/models/res_company.py#L143-L144 This methods calls _action_close_stock_valuation with a context modified with only self.env.company.ids in 'allowed_company_ids' https://github.com/odoo/odoo/blob/bfa39854e56da4bf23295d62f63d66973ad0d78e/addons/stock_account/models/res_company.py#L56 This is needed because inside stock_value() we use the total value of the product https://github.com/odoo/odoo/blob/bfa39854e56da4bf23295d62f63d66973ad0d78e/addons/stock_account/models/res_company.py#L92 which will be the sum of the values of the product for each company inside allowed_company_id https://github.com/odoo/odoo/blob/bfa39854e56da4bf23295d62f63d66973ad0d78e/addons/stock_account/models/product.py#L274 So in case action_close_stock_valuation() was called from the 'generate entry' button from the inventory valuation view we need only the main company selected to be in the 'allowed_company_ids' so that the inventory value is computed based only on this company (as is the accounting value). The problem is that this does not work when calling the method from _cron_post_stock_valuation because then there is no 'allowed_company_ids' in the context (because it was called from _process_job() with a new env). so self.env.company will be the company of the user which will be company 1. https://github.com/odoo/odoo/blob/bfa39854e56da4bf23295d62f63d66973ad0d78e/odoo/orm/environments.py#L243 Therefore when _action_close_stock_valuation will be called on company 2, in the context, allowed_company_ids will be company 1. Then, when computing 'products', with_company() will add self (company 2) to the context. https://github.com/odoo/odoo/blob/616e82d7b3a53b1facf481e783baed3e99393d3c/addons/stock_account/models/res_company.py#L151-L152 So stock_value will return the sum of the total_value of each product for company 1 and company 2 which is 40 (instead of 10 for just company 2) https://github.com/odoo/odoo/blob/616e82d7b3a53b1facf481e783baed3e99393d3c/addons/stock_account/models/res_company.py#L242 We then create the closing accounting entry to match the accounting value with the stock value, which explains why the new initial accounting balance of company 2 is 40. **fix:** We set the context using self instead of self.env.companies This makes more sense as both in the cron use case and the generate entry use case the stock value we want is the one of the company in self. - In cron use case, it's obvious as the method is called in a for loop on each company - In the generate entry use case, self will also be the main company, because it's called, in actionGenerateEntry, on this.companyId https://github.com/odoo/odoo/blob/616e82d7b3a53b1facf481e783baed3e99393d3c/addons/stock_account/static/src/stock_valuation/controller.js#L75 which is computed based on the get_report_values https://github.com/odoo/odoo/blob/616e82d7b3a53b1facf481e783baed3e99393d3c/addons/stock_account/static/src/stock_valuation/controller.js#L21 https://github.com/odoo/odoo/blob/616e82d7b3a53b1facf481e783baed3e99393d3c/addons/stock_account/static/src/stock_valuation/controller.js#L28-L30 Which returns the main company https://github.com/odoo/odoo/blob/616e82d7b3a53b1facf481e783baed3e99393d3c/addons/stock_account/report/stock_valuation_report.py#L29 Most importantly, this is also aligned with how the accounting values are computed. https://github.com/odoo/odoo/blob/616e82d7b3a53b1facf481e783baed3e99393d3c/addons/stock_account/models/res_company.py#L103-L105 opw-6237402 Forward-Port-Of: odoo/odoo#270127 Forward-Port-Of: odoo/odoo#266932
This update adds descriptive text to language selector flag images when the flag is the only visible indicator. It improves accessibility for screen reader users and gives search engines better context for the language options.
Original PR description
Steps to reproduce: 1. Enable the language selector in the website header. 2. Enable the "Inline" and "Flag" options. 3. Inspect the flag images rendered in the inline variant. Issue: Flag images in the list items have an empty `alt=""` attribute in "Flag only" mode, where the flag is the sole visual indicator of the language, making the selector inaccessible to screen readers and providing no context for search crawlers. Expected behavior: Inline + Flag should have a descriptive ALT tag since there is no adjacent text or code to identify the language, the flag is not decorative. opw-6246464 Forward-Port-Of: odoo/odoo#273025 Forward-Port-Of: odoo/odoo#271362
Features or functions removed from Odoo
This change removes an outdated Hong Kong HSBCNet module that had already been cleared out internally but still existed as an empty leftover file. It helps keep the codebase clean and avoids confusion about a module that is no longer in use.
Original PR description
The contents of this file were previously deleted, but the file itself was missed, leaving a dead l10n_hk_hsbcnet module in 19.4. This commit removes the file entirely to clean it up.
9 changes
Resolved issues and error corrections
The translation dialog now shows translated text with a cleaner, more consistent layout in normal use. In debug mode, translations are no longer preselected when multiple options exist, which helps avoid accidental choices and makes the confirmation button stay disabled until a selection is made.
Original PR description
Before the commit: the translated text is with green background color. In debug mode, the translation generated by the last translator is selected by default. After this commit: In non-debug mode, the translated text is now wrapped in a div and with a similar style as the previous versions. In debug mode, when there are multiple translators, the translated text is no longer automatically selected. When there's no translation selected, the confirm button is disabled. The translated texts are now wrapped inside gray/dark gary background color. task-6250193 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This change prevents the accounting automation from marking work as complete when an unexpected error occurs. As a result, failed items are less likely to be skipped silently, improving the reliability of scheduled posting tasks.
Original PR description
The previous fix commits progress even when an unexpected exception escaped the loop iteration when _autopost_draft_entries. Now progress is only committed on success or when a UserError is explicitly handled. Reference: https://github.com/odoo/odoo/pull/271509 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273115
Public links for shared audio files will no longer try to play in the browser preview. This avoids Chrome-specific preview failures and keeps the sharing experience consistent by downloading the file instead of exposing it as streaming media.
Original PR description
**Steps to reproduce:** - Install Documents app - Upload a sound file (mp3 for example, but the behavior is the same for other formats) - Share the document and copy the link - Log out - Paste the…
**Steps to reproduce:**
- Install Documents app
- Upload a sound file (mp3 for example, but the
behavior is the same for other formats)
- Share the document and copy the link
- Log out
- Paste the link
- Click on preview button
- Media is working fine on Firefox
- Media won't read on Chrome
```
Loading media from '' violates the following Content Security Policy directive: "default-src 'none'".
Note that 'media-src' was not explicitly set, so 'default-src' is used as a fallback.
The action has been blocked.
```
**Issue:**
Since [1] default CSP Headers are too strict for Chrome default media rendering, which breaks the file preview (and force user download).
This only impacts Chrome as they seem to render generate `<video><source>` elements to render the file which triggers a secondary request and fails due to the CSP constraint.
**Fix:**
Could re-apply the header fix of 17.4 (see [2]), but it seems better to block the preview of audio files as well by default (to match how we manage videos).
(Note: we don't want to be used as a media streaming platform)
[1] (set csp to none by default) https://github.com/odoo/odoo/commit/64beb80205dffe4b432c8b5813a3271b073fa85e
[2] (similar issue which was not fixed in 18.0+) https://github.com/odoo/enterprise/commit/a7af78eeb2b9763045a5bda8714172f5e7402df8
[3] (mp4 preview removed) https://github.com/odoo/enterprise/commit/ea88cf7c6d5f077b60fb59347659507fded0e2fe
opw-6235043
Forward-Port-Of: odoo/enterprise#119644The website cookie bar now keeps the intended spacing between buttons and links, even when edited in the page builder. This prevents the elements from appearing cramped or touching each other in the “Discrete” layout.
Original PR description
[FIX] website: preserve cookie bar button spacing Steps to reproduce: - Enable the cookies bar in the website settings. - Go to the website and enter edit mode. - Open the cookies bar from the invisible elements panel. - Select the "Discrete" layout in the options. => The buttons and link are rendered without the expected spacing. Before this commit, the client-side cookie bar template relied on whitespace-only text nodes to separate inline elements. Those nodes are not kept in the same way when the template is rendered by Owl, so selecting the layout could make adjacent buttons touch each other. After this commit, the spacing is carried by explicit Bootstrap spacing classes, so the rendered layout no longer depends on text nodes preserved by the XML formatting. task-6251151 Forward-Port-Of: odoo/odoo#272641 Forward-Port-Of: odoo/odoo#267488
Fixed an issue that could prevent POS managers from saving changes to a POS configuration when self-order images had been uploaded by someone else. This removes an unnecessary access error so teams can manage POS setups without needing Settings or Admin rights.
Original PR description
When editing a POS config, `_ensure_public_attachments` wrote `public=True` on the self-ordering background/home images on every write. These images are Many2many attachments created with a `res_model` but no `res_id`, so the attachment access check denies write to any non-system user who is not their creator.
As a result, a POS manager without Settings/Admin rights could not edit a config whose images were uploaded by another user (e.g. an admin during setup), getting:
AccessError: Sorry, you are not allowed to access this document.
(Operation: write) - Records: ir.attachment(...), User: ...
Steps to reproduce:
1. Enable self-ordering on a POS and select a background image
2. Set self-ordering back to disabled
3. Log in as a POS admin without Admin/Settings rights
4. Try to edit the POS -> error
opw-6331261
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#273299This update fixes an unreliable test in the Viva.com POS payment flow that could sometimes hang during automated runs. It now waits for the payment step to complete before sending the simulated webhook response, making the test process more stable and dependable.
Original PR description
The Viva.com POS tour was failing intermittentely due to the mocked webhook response not waiting for the payment/refund request to finish. This would cause the tour to hang as it missed the webhook confirmation. We fix the issue by changing the `waitingCard` status to only be set after the payment request returns, and wait for this status before sending the fake webhook response. runbot-243758 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273111
This update corrects the GSTR-1 export for SEZ invoices issued in foreign currency so the invoice value is shown in the company currency, INR, instead of the foreign currency amount. This helps ensure the GST return spreadsheet reflects the proper values for filing and reporting.
Original PR description
Currently, when generatign GSTR-1 return spreadshee, SEZ invoices issued in a foreign currency are exported with their totals in the foreign currency rather than the company currency (INR) Steps to reproduce: - Create a B2B SEZ invoice in foreign currency - Go to Accounting > Reporting > [India] GST Return periods - Generate the GSTR-1 report for the period Issue: In the resulting spreadsheet, the "Invoice Value" column takes the invoice total in USD rather then INR opw-6292913 Forward-Port-Of: odoo/enterprise#121972 Forward-Port-Of: odoo/enterprise#121157
This update fixes two manufacturing issues that could block production completion in certain multi-step and split-order scenarios. It ensures expected component quantities are correctly taken into account even when reservations are missing, and prevents an invalid negative reservation error when generating serial numbers on split manufacturing orders.
Original PR description
### Steps to reproduce: - In the settings enable: Multi-Steps Routes - Set your warehouse to manufacture in 2 steps (pick then manufacture). - Create a final product (FP) with a BOM in flexible…
### Steps to reproduce: - In the settings enable: Multi-Steps Routes - Set your warehouse to manufacture in 2 steps (pick then manufacture). - Create a final product (FP) with a BOM in flexible consumption: - 1 x COMP (lot tracked) - Create and confirm an MO for 1 units of FP - Set the quantity producing on the MO to 1 > The consumed qty was updated to 1 unit - Set a lot on the pre-production pikcing and validate #### > The lot is not transfered to the MO which you are not able to validate since the registered component is lot less ### Cause of the issue: The issue is caused by https://github.com/odoo/odoo/commit/3223deb871ca4cb4ac0381e4321f2dbf79a60189 as the `qty_waiting` is based on the reservation state of the move origin of the move rather than its actual demand: https://github.com/odoo/odoo/blob/00118002bd6eab2f4c34a32e993a9219fded06ac/addons/mrp/models/mrp_production.py#L1419-L1426 In particular, since the backorder of the pre-production picking was not reserved (since nothing was available in stock), it was not taken into account as it should have been. Issue 2: Steps to reproduce: - In the settings Enable Multi-Steps Routes - Unarchive MTO - Create 3 products: - Final Product: Tracked by SN with a BOM: 1 X Super Component - Super Component: Tracked by SN, MTO with a BOM: 1 X Component - Basic Component: Put 10 units in stock - Create and confirm an MO for 3 units of Final Product > This should create an MO for 3 units of Super Component - Go to the Child MO > Cogs wheel > Split in 3 MO's - Click "Generate serial" on each Child MO and validate the first one - On the MO for Final Product > Cogs wheel > Split in 3 MO's - On the first MO, click "Generate Serial" > Error: Reserving a negative quantity is not allowed. ### Cause of the issue: The `action_generate_serial` calls in turn the `set_qty_producing`: https://github.com/odoo/odoo/blob/9fac1400fe5a8e665732c2ee3701c17c3495318f/addons/mrp/models/mrp_production.py#L1601 However, since the main MO was split the Super component demand is of 1 but each child MO provide an origin quantity of 1 so that the `new_qty` will be set to a negative one here: https://github.com/odoo/odoo/blob/9fac1400fe5a8e665732c2ee3701c17c3495318f/addons/mrp/models/mrp_production.py#L1418-L1426 But, since the first child MO was validated, there is already a move line associated to the Super component move and the `_set_quantity_done` will therefore try to adapt the reservation to a negative quantity which leads to the error: https://github.com/odoo/odoo/blob/9fac1400fe5a8e665732c2ee3701c17c3495318f/addons/stock/models/stock_move_line.py#L469-L470 opw-6128575 opw-6317083 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273168 Forward-Port-Of: odoo/odoo#271123
This update resolves issues with the loyalty program module, ensuring new invoices correctly award points based on defined rules. Previously, the system defaulted to a flat point amount and incorrectly invoiced negative amounts when loyalty points were exhausted. This fix improves the accuracy and reliability of the loyalty program for our subscription customers.
Original PR description
This commit fixes the following problems in the new module: - New invoices sometimes could not grant points according to the specified rules. - The reward point mode was not being taken into account and was giving a flat amount of points. - Reward lines were being invoiced with a negative amount when there was no more points in the loyalty card. - The 'Recurring' option in conditional rules and reward were not showing sometimes for an unknown reason. task-6153127
12 changes
Enhancements to existing features
The Expense dashboard now follows the same filtering rules as the list view for the 'To Submit', 'Waiting Approval', and 'Waiting Reimbursement' states. This makes dashboard totals more accurate, for example allowing managers to see the amounts for the employees they supervise.
Original PR description
For the expense dashboard with the states 'To Submit', 'Waiting Approval' and 'Waiting Reimbursement', make these states compliants with the current filters of the list view. It means, for example, that a manager can see the total amounts of the people he manages. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273302 Forward-Port-Of: odoo/odoo#270234
This change removes technical e-reporting fields from standard invoice screens so everyday users see a cleaner, less confusing form. The same information is still available in the invoice chatter, where related flow, status, and blocking errors are recorded with a direct link to the e-reporting process. It also avoids unnecessary address validation errors on B2C invoices when they are not needed for this reporting flow.
Original PR description
E-reporting technical fields were displayed directly on invoices, adding noise for regular invoicing users. Hide the e-reporting status columns and technical block from the standard invoice views. Log the relevant e-reporting flow, status and blocking errors in the invoice chatter instead, with a link to the related flow. Also avoid reporting address validation errors on B2C invoices, as they are not required for Flux 10 e-reporting. Task-6273226 Forward-Port-Of: odoo/odoo#271865
The log viewer has been improved to stay responsive with very large log files by showing only the most recent entries. It also now keeps new messages in view only when you are already at the bottom, and removes extra noise such as color-code artifacts and self-generated log request entries.
Original PR description
This commit makes the following pages to the log viewing page: - Only the last 10000 lines of logs are shown. This stops the page from freezing/performing badly when the logfile is very large. - When the view is at the bottom of the page, new logs are automatically scrolled into view. Otherwise the view stays still so the user can inspect the logs without them scrolling away. - The ANSI color codes are now stripped from the logs as they were just displayed as garbage characters. - The requests to fetch logs are now removed from the output, as otherwise you would be spammed with requests that only happen as a result of the logging page being open. task-6330996 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Resolved issues and error corrections
The product classification code 10171500, for Organic fertilizers and plant nutrients, is now visible again in the UNSPSC list. This ensures users can select the correct code when setting up product accounting, avoiding missing classification options.
Original PR description
The code 10171500 - Organic fertilizers and plant nutrients wasn't appearing. In the file that has the unspsc product codes this one was set to False. Steps to reproduce: - Activate module product_unspsc. - Go to product > accounting. - Verify that this code is not listed. Ticket [link](https://www.odoo.com/odoo/project.task/4461974) opw-4461974 Forward-Port-Of: odoo/enterprise#121914
When a planned work order’s start time is changed, Odoo now keeps the original duration and recalculates the end time from it. This prevents unexpected duration changes and avoids cases where dependent work orders could end up with a zero duration.
Original PR description
**Problem:** On a planned work order, changing only the start date (e.g. in the planning gantt edit dialog) corrupts the expected duration instead of just shifting the end date. The duration drifts…
**Problem:** On a planned work order, changing only the start date (e.g. in the planning gantt edit dialog) corrupts the expected duration instead of just shifting the end date. The duration drifts to a wrong value, and in some cases (e.g. dependent work orders) collapses to 0. **Steps to reproduce:** 1. Plan a work order on a workcenter (start, end, expected duration). 2. Open it and change only the start date to a time that is not on a working-hours boundary. 3. The end date updates, but the expected duration is now wrong. **Expected behavior:** Changing the start date replans the work order: the duration is kept and the end date is recomputed from it. This is how 19.0 behaves and how dragging the pill in the gantt already behaves. **Cause of the issue:** Changing date_start triggers _onchange_date_start, which recomputes date_finished from start + duration via plan_hours. That cascades into _onchange_date_finished, which recomputes duration_expected from the dates via get_work_duration_data. Since the resource calendar refactor in 19.2, plan_hours and get_work_duration_data are no longer exact inverses around the work order's own planned slot, so the round trip drifts the duration. **Fix:** Only recompute the duration when the end date was edited on its own. When date_finished already matches the planned end for the current duration, it was merely derived from the start change, so the duration is kept. This keeps the duration authoritative when moving the work order while still recomputing it on a genuine end-date resize. opw-6231569
This change moves a few test checks to the correct module so builds run consistently in both full and single-app setups. It prevents false failures during validation and helps keep deployment checks reliable.
Original PR description
Oversight of: https://github.com/odoo/enterprise/pull/98569 Some assertions were put in the wrong module, making the builds work in "all apps" mode but fail in "single app" mode. This commit moves assertions where they belong. Task-6353709
This change makes Odoo better at processing email attachments from external systems that send an incomplete Content-Type value. Instead of risking file corruption, attachments are now stored correctly even when the email header is non-standard.
Original PR description
[[REF] mail: consolidate attachment Content-Type normalization](https://github.com/odoo/odoo/pull/273097/changes/ad4e34c5c79450b1e976d9ba7047487218690585) Two separate spots handled malformed…
[[REF] mail: consolidate attachment Content-Type normalization](https://github.com/odoo/odoo/pull/273097/changes/ad4e34c5c79450b1e976d9ba7047487218690585)
Two separate spots handled malformed Content-Type headers. Merge them
into one block, read the raw header once with partition(';') to have
both the type and its parameters available without re-fetching the
header for each case.
No behavior change.
[[FIX] mail: handle attachment Content-Type with no subtype](https://github.com/odoo/odoo/pull/273097/changes/7b410fbe606b7e476f0005485e42783834983b75)
Some mailers send attachments with a bare token as Content-Type instead
of a valid 'type/subtype' pair, e.g.:
Content-Type: base64; name="foo.pdf"
Content-Transfer-Encoding: base64
Python's email library normalises any MIME type without a '/' to
'text/plain'. get_content() then decodes the base64 payload as UTF-8
text, replacing invalid byte sequences with U+FFFD. The subsequent
encode('utf-8') bakes those replacements in, permanently corrupting
the stored file.
Per Postel's law [RFC 761], be liberal in what we accept: detect these
non-standard types via `not all(mimetype.partition('/'))` and fall back
to application/octet-stream, keeping the original parameters (filename,
charset, etc.) so the attachment is stored intact.
opw-6227526Gift receipts will no longer include the self-service invoicing QR code. This helps preserve the purpose of gift receipts by keeping pricing information hidden from the recipient.
Original PR description
Gift receipts are intended to be given to the gift recipient and are designed to hide product prices. The self-service invoicing QR code could expose pricing information through the generated invoice, defeating the purpose of the gift receipt. Therefore, remove the self-invoicing QR code from gift receipts. task-6299597 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This change restores a missing update when a phone call activity is marked as done. It ensures the related message is properly updated afterward, preventing inconsistencies in follow-up activity tracking.
Original PR description
In [1], we removed `action_call_done` for call activity, and to use `action_feedback` to mark a call activity done like other activities. However, we forgot to assign `activity_mail_message_id` for later mail message update. Add this in `action_feedback`. [1]: 70ba1812812596e00509415cedcc8f4bdf6c6e37 COMPR: https://github.com/odoo/odoo/pull/267663
When exporting an invoice to PDF, the VAT/TIN label will now appear in the customer’s chosen language instead of the employee’s language. This makes invoices clearer and more consistent for customers who receive documents in their preferred language.
Original PR description
Issue: While exporting an invoice as PDF, Customer VAT is translated according to user language instead of customer chosen language. Steps to reproduce: - In a Belgian company - Install Greek language, but keep English as user language - Create a Customer and select Greek as their language - Create an invoice - Export as PDF Current behavior: - VAT is displayed in user language Expected behavior: - VAT is displayed in customer language (ΦΠΑ) opw-6264065
This change removes the ability to create new journals directly from the journal search popup in places like Point of Sale payment methods. It helps keep journal setup controlled inside the Accounting app, avoiding accidental creation in the wrong context.
Original PR description
Currently on the pos payment method form, if you click "Select more" on the journal field, you will see two buttons 'New' & 'Create New'. Steps to reproduce: ------------------- * Open any pos…
Currently on the pos payment method form, if you click "Select more" on the journal field, you will see two buttons 'New' & 'Create New'. Steps to reproduce: ------------------- * Open any pos payment method * Select the journal field * Select "Search more" > See two creation buttons Why the fix: ------------ One button is the standard "On search more" button which can be hidden using options such as no_create, no_create_edit, ... The second button is defined on the list view for journals and since the search more uses the list view it shows the button as well. Currently we can do that with a context key to ensure that on the "real" list view it's still visible. Why do we want to hide those buttons? Asked the R&D accounting team, it should not be allowed to create journals on the fly. You should only be able to create them inside accounting app. This behavior is not limited to this view but will only be applied locally. The fix can however be applied everywhere where needed. Before the fix: ------------------- <img width="700" height="417" alt="image" src="https://github.com/user-attachments/assets/ca11ea13-c38e-40a1-9848-cbc5edc6226e" /> <img width="1507" height="887" alt="image" src="https://github.com/user-attachments/assets/1cde5d3b-3372-4aca-b5d0-2319bd82c1de" /> After the fix: ---------------- <img width="707" height="474" alt="image" src="https://github.com/user-attachments/assets/01dc7b42-43d6-4b18-a12d-54330d51b92b" /> <img width="1457" height="870" alt="image" src="https://github.com/user-attachments/assets/ff387d3f-f59c-47ad-abfe-a2003669db1a" /> opw-6131231
The Point of Sale payment method screen no longer offers one-click creation of accounting journals from the search dialog. This ensures journals are only created through the Accounting app, reducing accidental setup changes and keeping accounting controls consistent.
Original PR description
Currently on the pos payment method form, if you click "Select more" on the journal field, you will see two buttons 'New' & 'Create New'. Steps to reproduce: ------------------- * Open any pos…
Currently on the pos payment method form, if you click "Select more" on the journal field, you will see two buttons 'New' & 'Create New'. Steps to reproduce: ------------------- * Open any pos payment method * Select the journal field * Select "Search more" > See two creation buttons Why the fix: ------------ One button is the standard "On search more" button which can be hidden using options such as no_create, no_create_edit, ... The second button is defined on the list view for journals and since the search more uses the list view it shows the button as well. Currently we can do that with a context key to ensure that on the "real" list view it's still visible. Why do we want to hide those buttons? Asked the R&D accounting team, it should not be allowed to create journals on the fly. You should only be able to create them inside accounting app. Before the fix: ------------------- <img width="700" height="417" alt="image" src="https://github.com/user-attachments/assets/6b67a45b-6e52-4e02-a827-1aca5d8417ec" /> <img width="1507" height="887" alt="image" src="https://github.com/user-attachments/assets/077bc3ab-bc6e-42a1-85e6-adf778000b92" /> After the fix: ----------------- <img width="707" height="474" alt="image" src="https://github.com/user-attachments/assets/da2a43e3-01c0-44c5-b529-e73f21825150" /> <img width="1457" height="870" alt="image" src="https://github.com/user-attachments/assets/b658b95f-5bc3-4b7a-9e7c-8b182cab48a0" /> opw-6131231
8 changes
Resolved issues and error corrections
Audio files shared through Documents will no longer open in browser preview by default. This prevents preview failures in Chrome and avoids unexpected media streaming behavior when a shared link is opened.
Original PR description
**Steps to reproduce:** - Install Documents app - Upload a sound file (mp3 for example, but the behavior is the same for other formats) - Share the document and copy the link - Log out - Paste the…
**Steps to reproduce:**
- Install Documents app
- Upload a sound file (mp3 for example, but the
behavior is the same for other formats)
- Share the document and copy the link
- Log out
- Paste the link
- Click on preview button
- Media is working fine on Firefox
- Media won't read on Chrome
```
Loading media from '' violates the following Content Security Policy directive: "default-src 'none'".
Note that 'media-src' was not explicitly set, so 'default-src' is used as a fallback.
The action has been blocked.
```
**Issue:**
Since [1] default CSP Headers are too strict for Chrome default media rendering, which breaks the file preview (and force user download).
This only impacts Chrome as they seem to render generate `<video><source>` elements to render the file which triggers a secondary request and fails due to the CSP constraint.
**Fix:**
Could re-apply the header fix of 17.4 (see [2]), but it seems better to block the preview of audio files as well by default (to match how we manage videos).
(Note: we don't want to be used as a media streaming platform)
[1] (set csp to none by default) https://github.com/odoo/odoo/commit/64beb80205dffe4b432c8b5813a3271b073fa85e
[2] (similar issue which was not fixed in 18.0+) https://github.com/odoo/enterprise/commit/a7af78eeb2b9763045a5bda8714172f5e7402df8
[3] (mp4 preview removed) https://github.com/odoo/enterprise/commit/ea88cf7c6d5f077b60fb59347659507fded0e2fe
opw-6235043
Forward-Port-Of: odoo/enterprise#119644This update adjusts the order of fields in the Mexican SAT XML trial balance report so it matches the structure recommended by the tax authority. The report stays valid, but now follows the expected layout to reduce the risk of rejection or confusion when reviewing the file.
Original PR description
**Steps to reproduce:** - Install the `l10n_mx_reports` module and switch to a Mexican company. - Navigate to Accounting > Reporting > Trial Balance. - From the dropdown menu, click `SAT (XML)`. -…
**Steps to reproduce:** - Install the `l10n_mx_reports` module and switch to a Mexican company. - Navigate to Accounting > Reporting > Trial Balance. - From the dropdown menu, click `SAT (XML)`. - Open the generated XML file and inspect the `<BCE:Ctas>` nodes. **Observation:** - The generated XML uses the following attribute order: `Debe > NumCta > Haber > SaldoFin > SaldoIni` - However, the SAT-recommended structure is: `NumCta > SaldoIni > Debe > Haber > SaldoFin` **Root Cause:** At [1], the attributes of the `<BCE:Ctas>` node are defined in an order that differs from the SAT-recommended structure. While the XML remains valid, the generated report does not match the layout recommended by the Mexican government specification. **Fix:** This commit reorders the `<BCE:Ctas>` attributes to follow the SAT-recommended structure, aligning the generated XML with the behavior introduced at [2] for `saas-19.3`. backport-of: https://github.com/odoo/enterprise/pull/115374 [1]: https://github.com/odoo/enterprise/blob/cb9c19272309d793379fa4d23145162f72fa5552/l10n_mx_reports/data/templates/cfdibalance.xml#L15-L20 [2]: https://github.com/odoo/enterprise/blob/acf0929a88ec788aecd44f6b4c647e468dc0a319/l10n_mx_reports/data/templates/cfdibalance.xml#L17-L22 opw-6297711 Forward-Port-Of: odoo/enterprise#122469 Forward-Port-Of: odoo/enterprise#121440
This change ensures the background process that posts draft accounting entries only records its progress when it actually succeeds, or when a known user-facing error is handled. This prevents the system from incorrectly marking work as completed after an unexpected failure, which helps keep accounting operations reliable.
Original PR description
The previous fix commits progress even when an unexpected exception escaped the loop iteration when _autopost_draft_entries. Now progress is only committed on success or when a UserError is explicitly handled. Reference: https://github.com/odoo/odoo/pull/271509 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273115
This fix closes a loophole in the Point of Sale so employees with minimal permissions can no longer create negative quantity lines by typing the minus key on a keyboard. It keeps the keyboard behavior aligned with the disabled on-screen button, ensuring access rules are applied consistently.
Original PR description
Currently minimal rights employee cannot select the "+/-" button to have a negative quantity line. However if they have a keyboard and press the "-" key they can modify the quantity to negative. Steps to reproduce: ------------------- * Modify the shop settings, give some employee minimal rights * Open shop and use the minimal employee as cashier * Add a product to the order * Press the "-" key on the keyboard > The line quantity becomes -1 Why the fix: ------------ The button on the product screen is disabled for the employee with minimal rights https://github.com/odoo/odoo/blob/4a2aa33ded628200935b22c501a5f94c21dffb1f/addons/point_of_sale/static/src/app/screens/product_screen/product_screen.js#L154 We extend that to the input key "-". opw-6248098 Forward-Port-Of: odoo/odoo#267748
This fixes an issue that could block POS managers from saving changes to a POS configuration when self-order images had been uploaded by someone else. With this update, managers without Settings or Admin access can edit the POS normally, avoiding an access error during routine configuration work.
Original PR description
When editing a POS config, `_ensure_public_attachments` wrote `public=True` on the self-ordering background/home images on every write. These images are Many2many attachments created with a `res_model` but no `res_id`, so the attachment access check denies write to any non-system user who is not their creator.
As a result, a POS manager without Settings/Admin rights could not edit a config whose images were uploaded by another user (e.g. an admin during setup), getting:
AccessError: Sorry, you are not allowed to access this document.
(Operation: write) - Records: ir.attachment(...), User: ...
Steps to reproduce:
1. Enable self-ordering on a POS and select a background image
2. Set self-ordering back to disabled
3. Log in as a POS admin without Admin/Settings rights
4. Try to edit the POS -> error
opw-6331261
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#273299This change resolves a test failure affecting Swedish payment files when two related accounting features are installed together. It updates the test setup so the check matches the new payment file structure and keeps automated validation reliable.
Original PR description
Here https://github.com/odoo/enterprise/pull/114662 we changed the way the CdtrAgt node is used in the SEPA XML file for Sweden. But this change broke a test when both account_iso20022 & l10n_se_bban are installed, leading to a Non-expected child error. This commit skip the failling test if l10n_se_bban is installed, and add a new one to replace it. runbot-938366 runbot-938367 Forward-Port-Of: odoo/enterprise#122359 Forward-Port-Of: odoo/enterprise#121485
When customers book through Reserve with Google, Odoo now uses the name sent by Google instead of falling back to the email address. This means new contacts, booking titles, and attendee details display the customer’s real name, while existing contacts matched by email keep their current name.
Original PR description
When a customer books through Reserve with Google, the createBooking payload carries the booker given_name and family_name next to the email, but the handler passed only the normalized email to…
When a customer books through Reserve with Google, the createBooking payload carries the booker given_name and family_name next to the email, but the handler passed only the normalized email to _mail_find_partner_from_emails. The new res.partner was therefore created with its name falling back to the email, see https://github.com/odoo/odoo/blob/aa7b5921191a0ff53ef1cc32af99fe458c45c0da/addons/mail/models/res_partner.py#L177 That name then flows into the calendar.event name, the attendee common_name and the contact details, all showing the email instead of the customer name. The module has read neither field since it was added in https://github.com/odoo/enterprise/commit/2e855b910173b56e8501d0ebe9ee6f83ac5845bc. Build the booker name from given_name and family_name and pass it with the email through formataddr in google_reserve_booking_create, so a newly created partner is named after the customer. A partner matched on an existing email keeps its current name. Steps to reproduce: 1. Enable Reserve with Google on an appointment type. 2. Book a slot from Google Maps with given name John and family name Doe. 3. Open the created booking and its contact in Odoo. => the contact name is the email instead of John Doe Ticket [link](https://www.odoo.com/odoo/project/49/tasks/6232318) opw-6232318 Forward-Port-Of: odoo/enterprise#120604
The Helpdesk quick-create form now only shows customers that belong to the selected company, instead of customers from other allowed companies. This helps prevent accidentally choosing the wrong customer when users work across multiple companies.
Original PR description
Steps to reproduce: - Create two companies (Company A and Company B) - Create one partner in each company - Enable both companies for the user - Open Helpdesk and go to the tickets Kanban view for a Company A team. - In the quick create form, the customer dropdown shows customers from Company B Issue: - Customers from other companies are visible in the customer field, Cause: - The partner_id field in the quick create view had no domain, so it displayed partners from all allowed companies. Solution: - Added a domain on partner_id in the ticket quick create form view. task-4971466 Forward-Port-Of: odoo/enterprise#122358 Forward-Port-Of: odoo/enterprise#121944
3 changes
Resolved issues and error corrections
This change fixes a test failure affecting Swedish payment files when two related accounting modules are installed together. It keeps the test suite stable after a previous update to how creditor agent information is handled in SEPA exports.
Original PR description
Here https://github.com/odoo/enterprise/pull/114662 we changed the way the CdtrAgt node is used in the SEPA XML file for Sweden. But this change broke a test when both account_iso20022 & l10n_se_bban are installed, leading to a Non-expected child error. This commit skip the failling test if l10n_se_bban is installed, and add a new one to replace it. runbot-938366 runbot-938367 Forward-Port-Of: odoo/enterprise#122359 Forward-Port-Of: odoo/enterprise#121485
This fix ensures the SAF-T export uses the correct official grouping code when account numbers are sliced. It prevents the report from showing an incorrect code, helping maintain accurate statutory reporting.
Original PR description
Steps to reproduce: - change 1920 Banck account to 19204321 - go in general ledger and export to "SAF-T" Issue: The grouping code is 4321 Grouping code should match official grouping code. As a matter of fact the chart of account seems to match thos grouping account if we slice them correctly. opw-6285078 Forward-Port-Of: odoo/enterprise#121932
When a booking comes in through Reserve with Google, Odoo now uses the customer’s first and last name from Google instead of falling back to the email address. This means new contacts, appointment titles, and attendee details show the real customer name, while existing contacts matched by email keep their current name.
Original PR description
When a customer books through Reserve with Google, the createBooking payload carries the booker given_name and family_name next to the email, but the handler passed only the normalized email to…
When a customer books through Reserve with Google, the createBooking payload carries the booker given_name and family_name next to the email, but the handler passed only the normalized email to _mail_find_partner_from_emails. The new res.partner was therefore created with its name falling back to the email, see https://github.com/odoo/odoo/blob/aa7b5921191a0ff53ef1cc32af99fe458c45c0da/addons/mail/models/res_partner.py#L177 That name then flows into the calendar.event name, the attendee common_name and the contact details, all showing the email instead of the customer name. The module has read neither field since it was added in https://github.com/odoo/enterprise/commit/2e855b910173b56e8501d0ebe9ee6f83ac5845bc. Build the booker name from given_name and family_name and pass it with the email through formataddr in google_reserve_booking_create, so a newly created partner is named after the customer. A partner matched on an existing email keeps its current name. Steps to reproduce: 1. Enable Reserve with Google on an appointment type. 2. Book a slot from Google Maps with given name John and family name Doe. 3. Open the created booking and its contact in Odoo. => the contact name is the email instead of John Doe Ticket [link](https://www.odoo.com/odoo/project/49/tasks/6232318) opw-6232318 Forward-Port-Of: odoo/enterprise#120604
10 changes
Enhancements to existing features
This change removes technical e-reporting fields from standard invoice views, making invoices easier to read for regular users. The key e-reporting details and blocking issues are now shown in the chatter with a link to the related flow, and unnecessary address validation warnings are no longer shown on B2C invoices.
Original PR description
E-reporting technical fields were displayed directly on invoices, adding noise for regular invoicing users. Hide the e-reporting status columns and technical block from the standard invoice views. Log the relevant e-reporting flow, status and blocking errors in the invoice chatter instead, with a link to the related flow. Also avoid reporting address validation errors on B2C invoices, as they are not required for Flux 10 e-reporting. Task-6273226 Forward-Port-Of: odoo/odoo#271865
Backorder creation when validating very large receipts is now much faster and more reliable. The change reduces unnecessary processing and avoids database memory issues, helping large warehouse operations finish without timeouts.
Original PR description
## The Problem Validating receipts with a large number of operations by creating a backorder was timing out due to $O(N*M)$ filtering inside `_get_qty_received_without_self`, where N is the number of…
## The Problem Validating receipts with a large number of operations by creating a backorder was timing out due to $O(N*M)$ filtering inside `_get_qty_received_without_self`, where N is the number of moves in the picking, and M is the number of moves being processed for valuation. This happened while computing price units for moves one by one: each move filtered all picking moves to find the ones with the same `product_id`. Another issue was a PostgreSQL `"memory exhausted"` error caused by generating a large number of OR'ed conditions, equal to the number of processed moves. ## The Solution The massive filtering was fixed by filtering moves of the `purchase_line` instead of the `picking`, which is typically associated with only a few moves. This is still correct as the loop just after already ignores moves that don't have the same `purchase_line_id` of `self` anyways. The PostgreSQL error was fixed by grouping moves by `location_dest_id` and generating one condition per location using an `in` clause, which is typically much smaller than generating one condition per move. ## Benchmark Benchmark on a customer database, validating a receipt with 10k+ operations by creating a backorder: ```text Time: timeout -> 6 min ``` OPW-6272667 Forward-Port-Of: odoo/odoo#272603 Forward-Port-Of: odoo/odoo#269350
Resolved issues and error corrections
This update ensures that product barcodes are recognized correctly even when they also look like a GS1 barcode pattern. It prevents the system from mistaking a normal product scan for a quantity or lot scan, avoiding incorrect quantities being added to delivery lines.
Original PR description
In certain cases the barcode of a product could be a valid standalone GS1 sequence. In that case it needs to be be correctly interpreted as a product scan. ### Steps to reproduce: - In the settings…
In certain cases the barcode of a product could be a valid standalone GS1 sequence. In that case it needs to be be correctly interpreted as a product scan. ### Steps to reproduce: - In the settings enable "Default GS1 Nomenclature" - Create a storable product P with the barcode 3701762412212 - Create and confirm a delivery for 2 units of P and set the qty to 2 - Go to the barcode app and open your delivery - Scan 3701762412212 > The line of P is now selected with a quantity of 1/2 - Scan 3701762412212 #### > A new line is created for 1762411 units ### Cause of the issue: According to the GS1 nomenclature, the barcode 3701762412212 matches the scan of a quantity of "1762412" units of the lot name "2". As the scan of the of the product match a pattern for the GS1 nomenclature before matching a product, its barcode data is expected to be reset by these lines: https://github.com/odoo/enterprise/blob/7cceddaf086d849b8e2121e1023ef3479397534f/stock_barcode/static/src/models/barcode_model.js#L1320-L1324 In order to bypass the GS1 parser and to add 1 unit of the product. This is what happen on the first scan. However, performing the first scan also selects the associated line and, hence on the second scan the lines just above this check do set the product to match the product of the current line: https://github.com/odoo/enterprise/blob/7cceddaf086d849b8e2121e1023ef3479397534f/stock_barcode/static/src/models/barcode_model.js#L1294-L1320 In particular, we do not bypass the result provided by the GS1 parser and add `1762412` units of the product. opw-6175621 Forward-Port-Of: odoo/enterprise#122256 Forward-Port-Of: odoo/enterprise#120035
This update adjusts the order of fields in the Mexican trial balance XML export so it matches the structure recommended by the SAT. The report content stays the same, but the generated file now aligns better with government specifications and expected formatting.
Original PR description
**Steps to reproduce:** - Install the `l10n_mx_reports` module and switch to a Mexican company. - Navigate to Accounting > Reporting > Trial Balance. - From the dropdown menu, click `SAT (XML)`. -…
**Steps to reproduce:** - Install the `l10n_mx_reports` module and switch to a Mexican company. - Navigate to Accounting > Reporting > Trial Balance. - From the dropdown menu, click `SAT (XML)`. - Open the generated XML file and inspect the `<BCE:Ctas>` nodes. **Observation:** - The generated XML uses the following attribute order: `Debe > NumCta > Haber > SaldoFin > SaldoIni` - However, the SAT-recommended structure is: `NumCta > SaldoIni > Debe > Haber > SaldoFin` **Root Cause:** At [1], the attributes of the `<BCE:Ctas>` node are defined in an order that differs from the SAT-recommended structure. While the XML remains valid, the generated report does not match the layout recommended by the Mexican government specification. **Fix:** This commit reorders the `<BCE:Ctas>` attributes to follow the SAT-recommended structure, aligning the generated XML with the behavior introduced at [2] for `saas-19.3`. backport-of: https://github.com/odoo/enterprise/pull/115374 [1]: https://github.com/odoo/enterprise/blob/cb9c19272309d793379fa4d23145162f72fa5552/l10n_mx_reports/data/templates/cfdibalance.xml#L15-L20 [2]: https://github.com/odoo/enterprise/blob/acf0929a88ec788aecd44f6b4c647e468dc0a319/l10n_mx_reports/data/templates/cfdibalance.xml#L17-L22 opw-6297711 Forward-Port-Of: odoo/enterprise#122469 Forward-Port-Of: odoo/enterprise#121440
When a customer books an appointment through Reserve with Google, Odoo now uses the name provided in Google’s booking details instead of falling back to the email address. This ensures contacts, calendar entries, and attendee details display the customer’s real name, improving clarity for staff and customers.
Original PR description
When a customer books through Reserve with Google, the createBooking payload carries the booker given_name and family_name next to the email, but the handler passed only the normalized email to…
When a customer books through Reserve with Google, the createBooking payload carries the booker given_name and family_name next to the email, but the handler passed only the normalized email to _mail_find_partner_from_emails. The new res.partner was therefore created with its name falling back to the email, see https://github.com/odoo/odoo/blob/aa7b5921191a0ff53ef1cc32af99fe458c45c0da/addons/mail/models/res_partner.py#L177 That name then flows into the calendar.event name, the attendee common_name and the contact details, all showing the email instead of the customer name. The module has read neither field since it was added in https://github.com/odoo/enterprise/commit/2e855b910173b56e8501d0ebe9ee6f83ac5845bc. Build the booker name from given_name and family_name and pass it with the email through formataddr in google_reserve_booking_create, so a newly created partner is named after the customer. A partner matched on an existing email keeps its current name. Steps to reproduce: 1. Enable Reserve with Google on an appointment type. 2. Book a slot from Google Maps with given name John and family name Doe. 3. Open the created booking and its contact in Odoo. => the contact name is the email instead of John Doe Ticket [link](https://www.odoo.com/odoo/project/49/tasks/6232318) opw-6232318 Forward-Port-Of: odoo/enterprise#120604
The payment flow now confirms that the self-order point of sale is actually set up as a kiosk before continuing. It also checks that an IoT payment method is configured, helping prevent payment errors and reducing failed transactions.
Original PR description
This commit makes the payment endpoint more robust by verifying the POS config is indeed a kiosk, and that it has an IoT payment method configured. Forward-Port-Of: odoo/enterprise#121894
This update fixes a test failure that appeared when two Swedish payment-related modules were installed together. It keeps the payment export behavior stable by replacing the outdated test with one that matches the new file format, reducing the risk of false alarms in automated checks.
Original PR description
Here https://github.com/odoo/enterprise/pull/114662 we changed the way the CdtrAgt node is used in the SEPA XML file for Sweden. But this change broke a test when both account_iso20022 & l10n_se_bban are installed, leading to a Non-expected child error. This commit skip the failling test if l10n_se_bban is installed, and add a new one to replace it. runbot-938366 runbot-938367 Forward-Port-Of: odoo/enterprise#122359 Forward-Port-Of: odoo/enterprise#121485
Tracked URLs generated without an active website context now fall back to the system base URL instead of picking a company website at random. This ensures links created by background processes, such as mass mailing, point to the intended public domain and stay consistent across companies.
Original PR description
The [`_compute_short_url_host`](https://github.com/odoo/odoo/blob/a81fa8699c89385d2cccb260ada07255c6ea1275/addons/website_links/models/link_tracker.py#L20-L24) override builds link.tracker short URLs…
The [`_compute_short_url_host`](https://github.com/odoo/odoo/blob/a81fa8699c89385d2cccb260ada07255c6ea1275/addons/website_links/models/link_tracker.py#L20-L24) override builds link.tracker short URLs from `website.get_current_website()` and the current company's website domain. It was introduced by https://github.com/odoo/odoo/commit/f13ecb15af7f0bdc67e37dfb41e8bac77f5a541a for a multi-company backend flow (users switching companies to post social marketing links), but it runs for every compute, including CRON contexts with no HTTP request such as the mass-mailing queue. Without a request, `get_current_website()` picks an arbitrary website (the first in the database) and `self.env.company` resolves to the user's main company, so the short URL uses that company's website domain instead of `web.base.url`. Fall back to `super()._compute_short_url_host()` (which uses `web.base.url`) when no website is resolvable from the request, session, or context. Backend flows with a real request still hit the company-aware branch. Steps to reproduce: 1. Install Email Marketing and Website. 2. Settings > Companies: create a second company B. Settings > Websites: ensure website A points to company A with domain A, and create website B for company B with domain B. 3. Settings > Technical > Parameters > System Parameters: set `web.base.url` to a third domain C, and add `web.base.url.freeze` = `True`. 4. On company A, Email Marketing: create a mailing with body `<a href="http://example.com">test</a>` and a recipient list, then click Send. 5. Settings > Technical > Automation > Scheduled Actions > "Mass Mailing: Process queue" > Run Manually. 6. Email Marketing > Configuration > Link Tracker: open the tracker generated for the mailing. => The Tracked URL uses domain A. => The Tracked URL uses domain C. Ticket [link](https://www.odoo.com/odoo/project.task/6038590) opw-6038590 Forward-Port-Of: odoo/odoo#259200
The Timesheet app now correctly shows an employee’s own non-working days as unavailable in the My Timesheet view. This prevents users from seeing a day as available when it should be grayed out, helping avoid incorrect time entry.
Original PR description
To reproduce: ============= - modify Mitchel Admin's working schedule and remove a day of work - open timesheet app as Mitchel Admin - the removed day is not grayed out as unavailable Porblem: ======== the method `get_unavailabily` was handling only the case when calling it with `groupby=employee_id` otherwise it returns the company's unvailability Solution: ========= when the "My Timesheet" action is opened, the method `get_unavailabily` is now called with a specific context key, allowing to return the current user's unavailability instead of the company's one. opw-5949236 Forward-Port-Of: odoo/enterprise#122191 Forward-Port-Of: odoo/enterprise#113984
This fix prevents users from setting default values for fields they do not have permission to change. It helps keep default settings aligned with access rights and reduces the risk of unintended or unauthorized behavior.
Original PR description
Users should be able to set default values only for fields they have access to. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273230 Forward-Port-Of: odoo/odoo#273089
2 changes
Resolved issues and error corrections
This fix ensures the SAF-T export uses the correct official grouping code when account numbers are sliced. It prevents wrong codes from appearing in the general ledger export, improving the accuracy of accounting reports.
Original PR description
Steps to reproduce: - change 1920 Banck account to 19204321 - go in general ledger and export to "SAF-T" Issue: The grouping code is 4321 Grouping code should match official grouping code. As a matter of fact the chart of account seems to match thos grouping account if we slice them correctly. opw-6285078 Forward-Port-Of: odoo/enterprise#121932
Bookings made through Reserve with Google will now create contacts using the customer’s first and last name from Google, instead of falling back to the email address. This improves the accuracy of contact records and makes appointment details display the customer’s real name in Odoo.
Original PR description
When a customer books through Reserve with Google, the createBooking payload carries the booker given_name and family_name next to the email, but the handler passed only the normalized email to…
When a customer books through Reserve with Google, the createBooking payload carries the booker given_name and family_name next to the email, but the handler passed only the normalized email to _mail_find_partner_from_emails. The new res.partner was therefore created with its name falling back to the email, see https://github.com/odoo/odoo/blob/aa7b5921191a0ff53ef1cc32af99fe458c45c0da/addons/mail/models/res_partner.py#L177 That name then flows into the calendar.event name, the attendee common_name and the contact details, all showing the email instead of the customer name. The module has read neither field since it was added in https://github.com/odoo/enterprise/commit/2e855b910173b56e8501d0ebe9ee6f83ac5845bc. Build the booker name from given_name and family_name and pass it with the email through formataddr in google_reserve_booking_create, so a newly created partner is named after the customer. A partner matched on an existing email keeps its current name. Steps to reproduce: 1. Enable Reserve with Google on an appointment type. 2. Book a slot from Google Maps with given name John and family name Doe. 3. Open the created booking and its contact in Odoo. => the contact name is the email instead of John Doe Ticket [link](https://www.odoo.com/odoo/project/49/tasks/6232318) opw-6232318 Forward-Port-Of: odoo/enterprise#120604
13 changes
Enhancements to existing features
When a user manually sets allocated hours on a task, those values are now preserved even if the task dates change later. This prevents the system from overwriting user input and helps keep planning and time estimates consistent.
Original PR description
Before this commit, updating the planned start date or deadline recomputed the allocated hours automatically, even when the user had manually set a custom allocated hours value. In this commit ensures that once the allocated hours is manually updated by the user, the system marks the value as manually defined and prevents further automatic recomputation based on task scheduling changes.
The AI-related Discuss client action now uses a reactive signal for its action state instead of a plain property. This makes the interface update more reliably when the action changes, improving responsiveness and reducing the chance of stale behavior for users.
Original PR description
Pr community: https://github.com/odoo/odoo/pull/273286
A new “Daily Rates” smart button is added to rental pricelists, opening a calendar view of dated pricing rules. This makes it easier to review seasonal rates at a glance and create pricing periods by selecting dates directly on the calendar.
Original PR description
Seasonal rental prices are set through pricelist rules with validity dates. This commit adds a "Daily Rates" smart button on the pricelist that opens a month calendar of its dated rules, where selecting a period creates a single rule spanning it. task-4968689
The paid time off allocation process now automatically suggests postponed leave entries for employees who were absent during the relevant periods, reducing manual work during payroll runs. The interface also makes it easier to see which leaves are lost, postponed, or already allocated, improving clarity for payroll users.
Original PR description
Improve the paid time off allocation wizard by automatically suggesting postponed leaves for employees who were not working during the relevant periods and by enhancing the visibility of allocation information. - If an employee is absent in December, we prefill postpone N-1. - If an employee is absent the whole year, we prefill postpone N-2. - Improve the UI to better highlight lost leaves, postponed leaves, and already allocated leaves. - Remove the wizard form view, as the wizard is only used from the payrun flow and all form fields are hidden. Task: 6279404
The DMFA Occupation report no longer uses a fixed joint committee code. It now pulls the code from the payroll version’s own joint committee, which makes the reporting more accurate across different cases and reduces manual inconsistencies.
Original PR description
Prior to this commit, the JC code on DMFA Occupation was hardcoded to 200. This commit makes it dynamic by fetching the JC code from the version's joint committee. task-6352493
The Time & Attendance step is now hidden in Belgian payroll runs for all payroll structures except the Monthly Pay structure. This makes the process clearer and avoids showing a step that does not affect payslip calculations for those other payrun types.
Original PR description
Hide the Time & Attendance step in Belgian payruns for all payroll structures except the Monthly Pay structure, since attendance data does not affect payslip computation for the other structures. task: 6346664
This update enhances the payroll journal report by automatically filtering payruns, grouping data by salary rules and year, and displaying the salary rule name for clarity. It also includes a new employer cost measure and sorts the report by sequence number, improving data organization and reporting accuracy.
Original PR description
[IMP] hr_payroll: payroll journal improvement . Selected payrun is filtered by default in searchbar. . Default group_by for salary rule. . Code is added to display name of the salary rule for only payroll journal report. . The list is sorted by sequence number. task - 6311017
Resolved issues and error corrections
Shared audio files can no longer be previewed directly in the browser. This avoids playback issues in Chrome and keeps shared document links working consistently by directing users to download the file instead.
Original PR description
**Steps to reproduce:** - Install Documents app - Upload a sound file (mp3 for example, but the behavior is the same for other formats) - Share the document and copy the link - Log out - Paste the…
**Steps to reproduce:**
- Install Documents app
- Upload a sound file (mp3 for example, but the
behavior is the same for other formats)
- Share the document and copy the link
- Log out
- Paste the link
- Click on preview button
- Media is working fine on Firefox
- Media won't read on Chrome
```
Loading media from '' violates the following Content Security Policy directive: "default-src 'none'".
Note that 'media-src' was not explicitly set, so 'default-src' is used as a fallback.
The action has been blocked.
```
**Issue:**
Since [1] default CSP Headers are too strict for Chrome default media rendering, which breaks the file preview (and force user download).
This only impacts Chrome as they seem to render generate `<video><source>` elements to render the file which triggers a secondary request and fails due to the CSP constraint.
**Fix:**
Could re-apply the header fix of 17.4 (see [2]), but it seems better to block the preview of audio files as well by default (to match how we manage videos).
(Note: we don't want to be used as a media streaming platform)
[1] (set csp to none by default) https://github.com/odoo/odoo/commit/64beb80205dffe4b432c8b5813a3271b073fa85e
[2] (similar issue which was not fixed in 18.0+) https://github.com/odoo/enterprise/commit/a7af78eeb2b9763045a5bda8714172f5e7402df8
[3] (mp4 preview removed) https://github.com/odoo/enterprise/commit/ea88cf7c6d5f077b60fb59347659507fded0e2fe
opw-6235043
Forward-Port-Of: odoo/enterprise#119644This update corrects the reimbursement rate used for bicycle travel in Belgian payroll. It ensures employees are paid the intended amount instead of being capped too high, which avoids overpayments and makes payslips accurate.
Original PR description
Steps to reproduce: 1. Employee Setup: CP200, Worker 495, Bike 18 km, Car 60 km. 2. Action: Compute 05/2026 payslip (21 worked days) and close pay. Got 226.80€ (stuck at 10.80€/day cap) -> Expected 204.12€ (18 km × 2 × 21 days × 0.27€). Solution: change rule parameter values from 0.36 to 0.27 Task: 6334739
This change removes an unnecessary event handling qualifier in the online bank sync portal. It makes the code easier to maintain and reduces confusion for future updates, without changing the user experience.
Original PR description
The `.withTarget` qualifier for interactions events is widely misunderstood: it is not necessary in most cases. It is only required when the event handler is processed through an asynchronous callback (such as interactions' `debounced` or `locked`): in such a case, when the line `ev.currentTarget` is evaluated, the property has been lost and is not available anymore due to the async nature of the call. In all other cases, developers should prefer calling `ev.currentTarget` directly.
This update fixes a mislabeled description in the Swiss payroll monthly snapshot. It now correctly refers to monthly history instead of yearly history, which improves clarity for users and administrators.
Original PR description
The L10nCHEmployeeMonthlySnapshot model incorrectly stated "Swiss Employee yearly history" as a description. Fix the _description attribute to "Swiss Employee monthly history". Task: 6340659
Code cleanup and technical improvements
This change removes outdated internal configuration from several interface components. It does not change how users work in the product, but it helps keep the codebase simpler and easier to maintain.
Original PR description
These components never read props.slots (only t-call-slot/t-set-slot, which don't require it to be declared), so the schema entry was dead.
This update simplifies the testing environment by reducing unnecessary reliance on the test environment variable. The changes prepare for a future update that will replace the current environment setup with a more streamlined testing approach. This refactoring aims to improve test execution speed and maintainability.
Original PR description
\* account_reports,ai,documents,documents_spreadsheet,
spreadsheet_edition,timer,web_studio,web_studio_ai_fields
This commit reduces the explicit usage of env in tests like:
- `patchWithCleanup(env.services.*, *)`: converted to `mockService("*", *)`.
- `env.services.*`: converted to `getService("*")`.
- `const env = await makeMockEnv();`: `makeMockEnv` is still called but
the result is not used anymore. If needed we can still use `getMockEnv`.
This change is to prepare the removal of env in the future.
`makeMockEnv` will be replaced by a function `makeTestApp`.11 changes
New functionality added to Odoo
This update establishes the initial payroll framework for Oman, including a local working schedule, demo company and employee data, and a first version of the salary structure. It helps businesses test and prepare payroll processes that match local working patterns and compensation rules.
Enhancements to existing features
This update adds Russian translations to the Uzbekistan reporting documents. It helps businesses in Uzbekistan use these reports more easily, supporting adoption in a market where Russian is commonly used alongside Uzbek.
Original PR description
Uzbekistan's business environment requires Russian in addition to the official Uzbek language to ensure adoption. While localizations typically activate only statutory languages, Central Asian market realities justify this exception. task-6229114 -- I confirm I have signed the CLA and read the PR guidelines at [www.odoo.com/submit-pr](http://www.odoo.com/submit-pr)
Resolved issues and error corrections
When processing a package during barcode operations, the system now correctly recognizes it as the destination package instead of wrongly blocking it for containing other products. This prevents unnecessary errors during warehouse picking and lets operators complete transfers smoothly.
Original PR description
### Steps to reproduce: - In the settings Enable: Multi-steps Routes, Packages - Put your warehouse in delivery in 2-steps - On the Pick operation type in the barcode tab disable: "Allow extra…
### Steps to reproduce: - In the settings Enable: Multi-steps Routes, Packages - Put your warehouse in delivery in 2-steps - On the Pick operation type in the barcode tab disable: "Allow extra products" - Create two storable products P1 and P2 - On P2 > On hand > Update Quantity > New - Create a new line in WH/Output with a package POOK for 1 unit - Create a new internal transfer for 1 unit of P1 using the pick operation type so that the picking goes WH/Stock -> WH/Output - Set the quantity of the move to 1 unit and go to the barcode app - Open the Pick > Scan WH-STOCK > Scan P1 > Scan POOK #### > An error is raised: This package contains extra products and extra products are not allowed on this operation. #### Expected behavior: The package should be set as result package. ### Cause of the issue: In the `_processPackage`, a check that is done to ensure that the package scan will not add extraproduct to the picking if this operation is not allowed: https://github.com/odoo/enterprise/blob/5e4c8ecb0c644e21755570ed59cd8f6e9f618c8a/stock_barcode/static/src/models/barcode_picking_model.js#L2024-L2035 Unfortunately, this check is done just before a possible usage of the package as package dest. And, in that case, since we do not try to add any product to the picking the check is irrelevant anyway. opw-6303969
This fix ensures that product barcodes are recognized properly even when they could also be interpreted as a GS1 barcode format. As a result, scanning the same product multiple times will update the delivery quantity correctly instead of creating an incorrect extra line with a huge quantity.
Original PR description
In certain cases the barcode of a product could be a valid standalone GS1 sequence. In that case it needs to be be correctly interpreted as a product scan. ### Steps to reproduce: - In the settings…
In certain cases the barcode of a product could be a valid standalone GS1 sequence. In that case it needs to be be correctly interpreted as a product scan. ### Steps to reproduce: - In the settings enable "Default GS1 Nomenclature" - Create a storable product P with the barcode 3701762412212 - Create and confirm a delivery for 2 units of P and set the qty to 2 - Go to the barcode app and open your delivery - Scan 3701762412212 > The line of P is now selected with a quantity of 1/2 - Scan 3701762412212 #### > A new line is created for 1762411 units ### Cause of the issue: According to the GS1 nomenclature, the barcode 3701762412212 matches the scan of a quantity of "1762412" units of the lot name "2". As the scan of the of the product match a pattern for the GS1 nomenclature before matching a product, its barcode data is expected to be reset by these lines: https://github.com/odoo/enterprise/blob/7cceddaf086d849b8e2121e1023ef3479397534f/stock_barcode/static/src/models/barcode_model.js#L1320-L1324 In order to bypass the GS1 parser and to add 1 unit of the product. This is what happen on the first scan. However, performing the first scan also selects the associated line and, hence on the second scan the lines just above this check do set the product to match the product of the current line: https://github.com/odoo/enterprise/blob/7cceddaf086d849b8e2121e1023ef3479397534f/stock_barcode/static/src/models/barcode_model.js#L1294-L1320 In particular, we do not bypass the result provided by the GS1 parser and add `1762412` units of the product. opw-6175621 Forward-Port-Of: odoo/enterprise#122256 Forward-Port-Of: odoo/enterprise#120035
The Mexican trial balance XML report now follows the field order expected by the SAT specification. This helps ensure the generated file matches the government-recommended format and reduces the risk of validation or filing issues.
Original PR description
**Steps to reproduce:** - Install the `l10n_mx_reports` module and switch to a Mexican company. - Navigate to Accounting > Reporting > Trial Balance. - From the dropdown menu, click `SAT (XML)`. -…
**Steps to reproduce:** - Install the `l10n_mx_reports` module and switch to a Mexican company. - Navigate to Accounting > Reporting > Trial Balance. - From the dropdown menu, click `SAT (XML)`. - Open the generated XML file and inspect the `<BCE:Ctas>` nodes. **Observation:** - The generated XML uses the following attribute order: `Debe > NumCta > Haber > SaldoFin > SaldoIni` - However, the SAT-recommended structure is: `NumCta > SaldoIni > Debe > Haber > SaldoFin` **Root Cause:** At [1], the attributes of the `<BCE:Ctas>` node are defined in an order that differs from the SAT-recommended structure. While the XML remains valid, the generated report does not match the layout recommended by the Mexican government specification. **Fix:** This commit reorders the `<BCE:Ctas>` attributes to follow the SAT-recommended structure, aligning the generated XML with the behavior introduced at [2] for `saas-19.3`. backport-of: https://github.com/odoo/enterprise/pull/115374 [1]: https://github.com/odoo/enterprise/blob/cb9c19272309d793379fa4d23145162f72fa5552/l10n_mx_reports/data/templates/cfdibalance.xml#L15-L20 [2]: https://github.com/odoo/enterprise/blob/acf0929a88ec788aecd44f6b4c647e468dc0a319/l10n_mx_reports/data/templates/cfdibalance.xml#L17-L22 opw-6297711 Forward-Port-Of: odoo/enterprise#122469 Forward-Port-Of: odoo/enterprise#121440
The UNSPSC code 10171500, used for organic fertilizers and plant nutrients, is now available again in the product accounting list. This fixes the missing entry so users can correctly select it when classifying products.
Original PR description
The code 10171500 - Organic fertilizers and plant nutrients wasn't appearing. In the file that has the unspsc product codes this one was set to False. Steps to reproduce: - Activate module product_unspsc. - Go to product > accounting. - Verify that this code is not listed. Ticket [link](https://www.odoo.com/odoo/project.task/4461974) opw-4461974 Forward-Port-Of: odoo/enterprise#121914
This update corrects a test failure affecting Swedish SEPA payment files when two related accounting modules are installed together. It keeps the test suite reliable after a previous change to how creditor agent information is handled, without changing the intended payment behavior.
Original PR description
Here https://github.com/odoo/enterprise/pull/114662 we changed the way the CdtrAgt node is used in the SEPA XML file for Sweden. But this change broke a test when both account_iso20022 & l10n_se_bban are installed, leading to a Non-expected child error. This commit skip the failling test if l10n_se_bban is installed, and add a new one to replace it. runbot-938366 runbot-938367 Forward-Port-Of: odoo/enterprise#122359 Forward-Port-Of: odoo/enterprise#121485
When users put products into a package from the barcode app, the system will now show the package type selection when that option is enabled. This makes the barcode flow behave consistently with the standard warehouse process and prevents users from missing an important packaging choice.
Original PR description
### Steps to reproduce: - In the settings enable: Packages - On the operation type `Delivery Order` set "Set Package Type" - Create and confirm a delivery for 1 unit of a product P + reserve it - Got…
### Steps to reproduce: - In the settings enable: Packages - On the operation type `Delivery Order` set "Set Package Type" - Create and confirm a delivery for 1 unit of a product P + reserve it - Got to the barcode app to process the delivery - Scan your product and click "put in pack" #### > The put in pack wizard allowing you to set a package type on the new package does not pop up. ### Cause of the issue: As a general rule of thumb the wizard is suppose to be displayed when the option is enabled and when a package/package type is not already provided to the call: https://github.com/odoo/odoo/blob/5dbc448d336c7ff22803ae91d5014eb6d0a07234/addons/stock/models/stock_package.py#L332-L341 https://github.com/odoo/odoo/blob/5dbc448d336c7ff22803ae91d5014eb6d0a07234/addons/stock/models/stock_move_line.py#L1236-L1238 However an override was added to the barcode module so that the wizard is never displayed when the action is launched from the barcode app: https://github.com/odoo/enterprise/blob/673d449f38cd3eff27c44270c8f7edf91d0ecd02/stock_barcode/models/stock_move_line.py#L193-L196 The idea behind this override was that you could provide the package type id via scans and hence that is was not necessary. However, if you click directly on the put in pack button, the wizard still make sense and should therefore be displayed under the same conditions. opw-6325092
Bookings made through Reserve with Google will now create contacts using the customer’s actual name when it is provided. This prevents new bookings from showing an email address instead of the person’s name in the contact card, calendar event, and attendee details.
Original PR description
When a customer books through Reserve with Google, the createBooking payload carries the booker given_name and family_name next to the email, but the handler passed only the normalized email to…
When a customer books through Reserve with Google, the createBooking payload carries the booker given_name and family_name next to the email, but the handler passed only the normalized email to _mail_find_partner_from_emails. The new res.partner was therefore created with its name falling back to the email, see https://github.com/odoo/odoo/blob/aa7b5921191a0ff53ef1cc32af99fe458c45c0da/addons/mail/models/res_partner.py#L177 That name then flows into the calendar.event name, the attendee common_name and the contact details, all showing the email instead of the customer name. The module has read neither field since it was added in https://github.com/odoo/enterprise/commit/2e855b910173b56e8501d0ebe9ee6f83ac5845bc. Build the booker name from given_name and family_name and pass it with the email through formataddr in google_reserve_booking_create, so a newly created partner is named after the customer. A partner matched on an existing email keeps its current name. Steps to reproduce: 1. Enable Reserve with Google on an appointment type. 2. Book a slot from Google Maps with given name John and family name Doe. 3. Open the created booking and its contact in Odoo. => the contact name is the email instead of John Doe Ticket [link](https://www.odoo.com/odoo/project/49/tasks/6232318) opw-6232318 Forward-Port-Of: odoo/enterprise#120604
This update cleans up data before it is sent to the Belgian POS blackbox, reducing the risk of rejected or inconsistent records. It also makes cashier clock-in and clock-out behavior more reliable, especially when the register is idle or multiple actions happen at once.
Original PR description
Trim strings data before sending to the blackbox. Also make clock-in/out more robust: - call handleClockInOut through a Mutex to avoid concurrent races - clock the cashier out when the idle SaverScreen is shown FW of this PR: https://github.com/odoo/enterprise/pull/122471
This update checks whether an invoice was already received by DIAN before sending it again. If DIAN already has the document, Odoo now marks it as accepted instead of retrying and getting stuck on a duplicate-processing error. This helps prevent invoices from being blocked when the first response was delayed or lost.
Original PR description
When a customer invoice is sent to the DIAN. This call can time out the DIAN is frequently slow or momentarily unavailable while the DIAN has in fact already received, validated and stored the…
When a customer invoice is sent to the DIAN. This call can time out the DIAN is frequently slow or momentarily unavailable while the DIAN has in fact already received, validated and stored the document. The response never reaches Odoo, the exchange is recorded as `invoice_sending_failed`, and the accepted CUFE is never linked back to the move. On the next attempt Odoo re-POSTs the same invoice number. The DIAN validates only one transmission per document and rejects the second with rule 90, "Documento procesado anteriormente" (document already processed). The invoice is then stuck: the DIAN considers it accepted, Odoo considers it failed, and it can never be moved forward because every resend reproduces the same rejection. Instead of blindly re-transmitting, we now check whether the document already exists at the DIAN. When the move already carries a document in `invoice_sending_failed`, `_send_to_dian()` extracts the CUFE from the signed XML and calls the new `_get_status_by_cufe()` helper, which queries the `GetStatus` web service for that CUFE. If the DIAN confirmed it, the document is reconciled to `invoice_accepted` storing the DIAN message and the confirmed CUFE and no second transmission is made. In every other case the helper returns None and the existing `SendBillSync` flow proceeds unchanged. Keying the lookup on the CUFE makes this safe against false positives. A genuine lost acknowledgement yields the very same CUFE, so a matching valid CUFE at the DIAN is by construction the same document and can be accepted without any field-by-field comparison.
8 changes
Resolved issues and error corrections
This update prevents the Spanish Verifactu e-invoicing module from running out of memory or timing out during installation on databases that already contain accounting entries. It makes the setup process more reliable and reduces the risk of failed installations for existing customers.
Original PR description
### Description: When trying to install the module `l10n_es_edi_verifactu` on a database that already has moves, it is possible to encounter a timeout or a memory error. This is caused by the compute `l10n_es_edi_verifactu_state` and `l10n_es_edi_verifactu_clave_regimen`, both compute linked to the new model `l10n_es_edi_verifactu.document`. ### Reference: opw-6293590 Forward-Port-Of: odoo/odoo#271550
This fix prevents incorrect slicing of account numbers when generating the SAF-T export. As a result, the grouping code now matches the official format, ensuring the exported accounting data is accurate.
Original PR description
Steps to reproduce: - change 1920 Banck account to 19204321 - go in general ledger and export to "SAF-T" Issue: The grouping code is 4321 Grouping code should match official grouping code. As a matter of fact the chart of account seems to match thos grouping account if we slice them correctly. opw-6285078 Forward-Port-Of: odoo/enterprise#121932
This update restores the earlier Turnstile callback handling so website forms continue to work reliably. It addresses a compatibility issue introduced by a Cloudflare change that caused some challenge callbacks to fail.
Original PR description
Callbacks were changed to use a single shared callback instead of a bunch of callbacks that captured a specific container. Cloudlfare since introduced a change that breaks this change by not making "this" available inside callbacks. We thus go back to the previous implementation that did not rely on implementation details of the external widget. related: 5aa5cf62a9d3f2b0c862b0aab337b22367843fa6 Forward-Port-Of: odoo/odoo#273336
This update adds backend checks when users sign up for stock notification emails. It prevents subscriptions for products that are not available and stops public visitors from using an email address already tied to a registered account, reducing the risk of misuse.
Original PR description
Description of the issue/feature this PR addresses: Currently, in the website_sale_stock module, there is no backend validation when subscribing to notifications for products without stock. This…
Description of the issue/feature this PR addresses: Currently, in the website_sale_stock module, there is no backend validation when subscribing to notifications for products without stock. This allows public users to potentially use emails that belong to registered accounts. Current behavior before PR: Users could subscribe to stock notifications for products that don’t exist or cannot be added (no stock). Public users could use emails already associated with registered accounts, allowing them to subscribe on behalf of another user. No validation is enforced, leading to potential security issues. Desired behavior after PR is merged: Adding a subscription for a non-existent or unavailable product raises a ValidationError. Public users trying to subscribe with an email that belongs to a registered user receive an AccessError prompting them to sign in first. Backend validation prevents misuse of registered user emails and improves security. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#271880
This change prevents byproduct quantities from being reset to zero when a manufacturing order is unreserved and then re-checked for availability. It ensures byproducts are still produced correctly, avoiding missing output on production orders with byproducts.
Original PR description
On a mo that has byproducts, if you unreserve, it will also set the quantity of byproducts to 0 Steps to reproduce: ------------------- * Create a Products main, component and byproduct * Create a…
On a mo that has byproducts, if you unreserve, it will also set the quantity of byproducts to 0 Steps to reproduce: ------------------- * Create a Products main, component and byproduct * Create a bom for main with component as component and byproduct as byproduct * Create and confirm a mo for main * Set qty_producing to quantity ot produce * click on "Unreserve" (do_unreserve) * click on "Check availability" (action_assign) * Produce All -> the byproducts will not be produced. Observation: ------------- When updating the qty_producing value it will also update the quantity of the byproducts moves: https://github.com/odoo/odoo/blob/77b180e8251fb8019e0034e1c2f485fd2c34ea4e/addons/mrp/models/mrp_production.py#L892-L893 https://github.com/odoo/odoo/blob/77b180e8251fb8019e0034e1c2f485fd2c34ea4e/addons/mrp/models/mrp_production.py#L1350 https://github.com/odoo/odoo/blob/77b180e8251fb8019e0034e1c2f485fd2c34ea4e/addons/stock/models/stock_move.py#L2382 The quantity on the byproducts move has been updated. When clicking on Unreserve it will call do_unreserve, https://github.com/odoo/odoo/blob/aca2e226143487b421f79194d677bb48d5da1358/addons/mrp/models/mrp_production.py#L2297-L2298 It will filters the moves that do not need to be unreserved and select the others: https://github.com/odoo/odoo/blob/aca2e226143487b421f79194d677bb48d5da1358/addons/stock/models/stock_move.py#L900 and it will unlink all the sml from the moves: https://github.com/odoo/odoo/blob/aca2e226143487b421f79194d677bb48d5da1358/addons/stock/models/stock_move.py#L919 Which will set the quantity on the byproduct moves to 0. When Producing all (button_mark_done) since the qty_producing has already been set, it will simply mark the byproduct move has picked. https://github.com/odoo/odoo/blob/aca2e226143487b421f79194d677bb48d5da1358/addons/mrp/models/mrp_production.py#L1323-L1324 In our case, this means that the no byproducts will be created since, the quantity was previously set to 0 opw-6296562
Tracked links created by email marketing will now use the company’s configured base domain when there is no website page context available, instead of picking a random website domain. This avoids links being generated with the wrong address in background processing, such as scheduled mailing queues, and keeps outbound links consistent with the system settings.
Original PR description
The [`_compute_short_url_host`](https://github.com/odoo/odoo/blob/a81fa8699c89385d2cccb260ada07255c6ea1275/addons/website_links/models/link_tracker.py#L20-L24) override builds link.tracker short URLs…
The [`_compute_short_url_host`](https://github.com/odoo/odoo/blob/a81fa8699c89385d2cccb260ada07255c6ea1275/addons/website_links/models/link_tracker.py#L20-L24) override builds link.tracker short URLs from `website.get_current_website()` and the current company's website domain. It was introduced by https://github.com/odoo/odoo/commit/f13ecb15af7f0bdc67e37dfb41e8bac77f5a541a for a multi-company backend flow (users switching companies to post social marketing links), but it runs for every compute, including CRON contexts with no HTTP request such as the mass-mailing queue. Without a request, `get_current_website()` picks an arbitrary website (the first in the database) and `self.env.company` resolves to the user's main company, so the short URL uses that company's website domain instead of `web.base.url`. Fall back to `super()._compute_short_url_host()` (which uses `web.base.url`) when no website is resolvable from the request, session, or context. Backend flows with a real request still hit the company-aware branch. Steps to reproduce: 1. Install Email Marketing and Website. 2. Settings > Companies: create a second company B. Settings > Websites: ensure website A points to company A with domain A, and create website B for company B with domain B. 3. Settings > Technical > Parameters > System Parameters: set `web.base.url` to a third domain C, and add `web.base.url.freeze` = `True`. 4. On company A, Email Marketing: create a mailing with body `<a href="http://example.com">test</a>` and a recipient list, then click Send. 5. Settings > Technical > Automation > Scheduled Actions > "Mass Mailing: Process queue" > Run Manually. 6. Email Marketing > Configuration > Link Tracker: open the tracker generated for the mailing. => The Tracked URL uses domain A. => The Tracked URL uses domain C. Ticket [link](https://www.odoo.com/odoo/project.task/6038590) opw-6038590 Forward-Port-Of: odoo/odoo#259200
The rental module now includes the required scheduling component so its timeline view opens correctly. This prevents errors when users access rental planning screens and improves reliability for day-to-day operations.
Original PR description
Module was introduced without a dependency on the `web_gantt` module despite using `gantt` views. Already fixed in 19+ runbot error 237883 Forward-Port-Of: odoo/enterprise#122136
Documentation and clarification updates
This update fixes the license metadata for several community modules so they are marked with the correct LGPL-3 license instead of an enterprise license. It helps ensure the modules are labeled consistently and accurately for legal and distribution purposes.
Original PR description
Before this commit, the license set on manifest of some modules uses the enterprise license instead of `LGPL-3` license since it is a community module. This commit changes the license to set `LGPL-3`. Fixes #205134
5 changes
Enhancements to existing features
The shipping setting previously called “Batch Shipping” has been renamed to “Multicollo” in Sendcloud. This makes the wording match Sendcloud’s own terminology and reduces confusion for users configuring delivery options.
Original PR description
In order to avoid confusion for the customer, "Use Batch Shipping" was renamed to "Use Multicollo".This way it is consistent with the terminology used by Sendcloud. task-6048477
Resolved issues and error corrections
When a user changes the account on a vendor bill line and manually removes the suggested tax, Odoo now keeps that removal instead of restoring the tax automatically. This prevents incorrect totals and avoids showing an included tax as if it were added on top of the price.
Original PR description
Steps to reproduce: - Create a vendor bill, one journal item: no product, price 100, no tax -> save - Change the account of the line to one having a default included tax - Remove the suggested tax ->…
Steps to reproduce: - Create a vendor bill, one journal item: no product, price 100, no tax -> save - Change the account of the line to one having a default included tax - Remove the suggested tax -> save Issue: The tax is back on the line, applied on top of the price (100 -> 117.36), making the included tax look like an excluded one. Cause: `_inverse_account_id` is the inverse of `account_id` and its onchange, and retriggers `_compute_tax_ids` on every write of `account_id`. When the user removes the tax the onchange just suggested, javascript `_getChanges` does not identify the user-deleted tax and sends back only the new account_id <-> `tax_ids` is back to its server value. So the field is not protected by `_get_protected_vals` and the compute reapplies the default taxes of the account, overriding the user. Solution: Split the method in two: the onchange keeps suggesting the default taxes (when the user keeps them, the client sends `tax_ids` explicitly), the real inverse only keeps the analytic part. The create path is not impacted: `tax_ids` is precomputed from the account, so imports of new bills/entries still get the default taxes. opw-6088331
The Gantt view now loads correctly when tasks are grouped by sale order item. This fixes an error caused by a renamed field, restoring access to the progress display and preventing a broken screen for users.
Original PR description
### Steps to reproduce - Install `sale_timesheet_enterprise`. - Go to **Tasks → All Tasks**. - Switch to the **Gantt** view. - Group by **Sale Order Item** (`sale_line_id`). ### Issue A traceback is…
### Steps to reproduce - Install `sale_timesheet_enterprise`. - Go to **Tasks → All Tasks**. - Switch to the **Gantt** view. - Group by **Sale Order Item** (`sale_line_id`). ### Issue A traceback is raised when loading the Gantt view with group by `sale_line_id`: ```text ValueError: Invalid field 'planned_hours' on model 'project.task' for 'planned_hours:sum' ``` ### Root cause The Gantt progress bar computation for the `sale_line_id` grouping performs a `_read_group()` aggregation on the `planned_hours` field of `project.task`. However, `planned_hours` was renamed to `allocated_hours` during the saas-16.5 migration, so the former field no longer exists on `project.task`. As a result, the aggregation raises a `ValueError`. Migration reference: https://github.com/odoo/upgrade/blob/e638c6ce00d9d8936d034ad7130fef51565b9195/migrations/project/saas~16.5.1.2/pre-migrate.py#L10 Issued PR: https://github.com/odoo/enterprise/pull/49685 ### Fix Use `allocated_hours`, the renamed equivalent of `planned_hours`, when computing the Gantt progress bar. This restores the Gantt view when grouping tasks by **Sale Order Item** and prevents the traceback.
This fix makes the Odoo server more reliable when it is automatically reloading after file changes. It prevents rare timing issues that could cause the service to stop unexpectedly, especially in containerized environments, while keeping normal shutdown behavior unchanged.
Original PR description
### Summary When `dev_mode` includes `reload`, `ThreadedServer`'s FSWatcher reacts to a file change by sending the process a `SIGHUP` to trigger a phoenix restart. `signal_handler` turns `SIGHUP`…
### Summary When `dev_mode` includes `reload`, `ThreadedServer`'s FSWatcher reacts to a file change by sending the process a `SIGHUP` to trigger a phoenix restart. `signal_handler` turns `SIGHUP` into `KeyboardInterrupt`, which `ThreadedServer.run()`'s wait-loop catches. The catch is too narrow — a reload `SIGHUP` can kill the process through **three** windows that all sit outside the wait-loop's `try/except`, so the exception escapes `run()`/`main()`. Under Docker's default `restart: no`, PID 1 dies and the container stays down. ### The three windows 1. **Teardown duplicate (exit 130).** One file change can emit several FS events; the FSWatcher's `if not odoo.phoenix:` dedup races across threads and fires more than one `SIGHUP`. The first begins the phoenix teardown; the second lands during `stop()` / `watcher.stop()` / `_reexec()` and `KeyboardInterrupt` escapes. 2. **Exec-gap (exit 129).** `os.execve()` resets caught signal handlers to their default disposition (`SIGHUP` terminates) but preserves `SIG_IGN`; a `SIGHUP` arriving after the exec but before the re-exec'd process re-installs its handler kills the process outright. 3. **Startup (exit 130).** In the re-exec'd process, a `SIGHUP` anywhere in the startup section that precedes the wait-loop — `start()`, `preload_registries()` **and** `cron_spawn()` — escapes `run()`. ### Reproducer (deterministic) Boot a `ThreadedServer` (`--workers 0`) on any initialised db, then signal PID 1 a few times in quick succession: ```bash docker exec <container> sh -c 'i=0; while [ $i -lt 8 ]; do kill -HUP 1; sleep 0.1; i=$((i+1)); done' ``` Unpatched the process exits 130 or 129. Patched it stays up after one clean phoenix reload. Verified live on 17.0 and 18.0: stock `server.py` dies; the patched `server.py` survives sustained bursts (20/20 across repeated reload cycles on each version); `SIGINT`/`SIGTERM` still exit 0. ### Fix Minimal, in `signal_handler` + `run()` + `_reexec()`; `SIGINT`/`SIGTERM` untouched; one new instance attribute, no new module globals: - **Teardown duplicate:** ignore a `SIGHUP` once `quit_signals_received` is set (a restart/shutdown is already pending; the re-exec reloads fresh code). - **Startup:** a per-instance `in_preload` flag marks the entire startup section (`start()` + `preload_registries()` + `cron_spawn()`); a `SIGHUP` there sets the phoenix flag + counter and returns instead of raising, so the wait-loop exits right after startup and runs the normal restart. - **Exec-gap:** `signal.signal(signal.SIGHUP, signal.SIG_IGN)` just before `os.execve` so a `SIGHUP` in the gap is dropped rather than terminating the process. ### Related - #21209 (merged) — introduced the phoenix flag; did not guard these windows. - #206898 (merged), #207930 (open) — PreforkServer reload. ### CLA Covered by Codeforward B.V.'s corporate CLA; #269240 adds me to its contributor list (pending merge).
This update ensures emails sent from multi-website flows use the website the user actually started from, instead of accidentally falling back to another site. It prevents appointment and event links in customer emails from sending people to the wrong website, which could block them from managing their booking or registration.
Original PR description
In Multiwebsite settings, when the public user interactions needs email generation (appointment or event flow), the email links are generated with a base url that does not corresponds to the one from…
In Multiwebsite settings, when the public user interactions needs email generation (appointment or event flow), the email links are generated with a base url that does not corresponds to the one from which the request started. Case 1: - Have website A and website B - Create an appointment page website A - Log in via website B - As public user, make an appointment in Website A - Check the generated email Issue: button links in the email will redirect to the wrong website, so users will encounter an issue when managing the appointment. This occurs because when an user log in, the system parameter 'web.base_url' is updated with the current url. This parameter is then used as fallback when we need to retrieve the base url without an active record Case 2: - Have website A and website B - Create an event and assign it to website B - As public user, access the event and register to it - Check the generated email Issue: button links in the email will redirect to the wrong website, so users will encounter an issue when managing the event. This occurs because the record `event.registration` has no website_id field and the base url is taken from the company default website (website A) opw-4146760 opw-4336369 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