Wednesday, March 18, 2026
18 changes · 18.0
Enhancements to existing features
This update enhances our testing process by allowing developers to easily specify the Chrome/Chromium browser version used during tests. This simplifies debugging issues related to browser-specific problems and ensures consistent testing across different browser versions. It's a small change that improves our ability to quickly identify and resolve browser-related bugs.
Original PR description
This is mainly used to more easily provide an arbitrary version of Chrome/Chromium to debug browser's version specific breaking changes. Forward-Port-Of: odoo/odoo#253630
Resolved issues and error corrections
This update corrects a previous error that prevented freelancers from exporting payroll data to SDWorx. The change ensures that the system no longer flags missing SDWorx codes for freelancers, streamlining the export process. This resolves a user-reported issue impacting Belgian companies using the SDWorx integration.
Original PR description
Steps to reproduce: ------------------------------- 1. Install `l10n_be_hr_payroll_sd_worx` module 2. Switch the active company to a Belgian company 3. Go to Employees and create a new employee. Set the Employee Type to Freelancer from HR Settings page. 4. Navigate to Payroll > Reporting > Export Work Entries to SDWorx Observation: ------------------------------- A user error is raised stating: ``` There is no SDWorx code defined for the following employees ``` Issue: ------------------------------- The filter checking for missing SDWorx codes did not exclude employees with the Freelance employee type. SDWorx code does not passed to the freelancers Solution: ------------------------------- Add a condition to the employee filter to exclude freelance employees from the SDWorx code validation. opw-5387342 Forward-Port-Of: odoo/enterprise#102211
This update resolves a problem where header border widths were incorrectly set to full widths due to a design flaw in the input field. The change ensures consistent border behavior for standard headers while still allowing full borders for specific header templates. This improves the visual consistency of Odoo websites.
Original PR description
Previously, the border width input for headers allowed multiple values. This was required for specific header templates (e.g. rounded box) that use a full border. However, most headers only apply a border on the bottom. When the input had multiple values, the scss would break, resulting in full border. This change ensures that, for headers without the .o_full_border class, only the first value of the saved border width is used. As a result, the input behaves like a single-value field (similar to font size inputs) for standard headers, while still supporting multiple values for templates that require a full border. Steps to reproduce the issue: - Go to Edit mode - Click on the Header - In the Border option, enter "1 2" and leave the input to validate => The input display "3" and the header has a full border. task-5500516 Forward-Port-Of: odoo/odoo#244415
This update improves how charges are handled on invoices generated using UBL/BIS3. Previously, charges created separate invoice lines. Now, the charge amount is directly added to the original invoice line's price unit, streamlining invoice creation and ensuring accurate financial reporting. This change simplifies the process for users and improves data consistency.
Original PR description
Before this commit: A charge in an InvoiceLine was creating a new invoice line with the amount of the charge. After this commit: The charge is added in the price unit of the original line --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update resolves an issue where the copyright background color wouldn't display correctly on the website footer if the footer itself had no background color. The change adds a fallback value to the CSS, ensuring the copyright color is always visible regardless of the footer's background setting. This improves the website's appearance and consistency.
Original PR description
Before this commit, a css error would happen when the user tried to change the copyright background color if the footer had no background color.
This was due to $-footer-color not having a fallback value when neither o-color('footer-custom') nor o-color('footer') was defined.
This commit adds a fallback value to fix the issue.
task-5452457
Forward-Port-Of: odoo/odoo#248283This update resolves a bug where subscriptions would incorrectly reopen after a credit note payment was processed. The fix prevents the system from reopening subscriptions when a 'refund' payment is made, ensuring subscriptions remain in the correct 'churned' state. This improves subscription management accuracy.
Original PR description
Steps to reproduce: ------------------------------ 1. Install Subscription module 2. Create a new subscription and confirm it 3. Create an invoice from the subscription. * Register a payment and…
Steps to reproduce: ------------------------------ 1. Install Subscription module 2. Create a new subscription and confirm it 3. Create an invoice from the subscription. * Register a payment and ensure the invoice is in the Paid state. 4. Go back to the subscription and close it with any reason 5. Open the related invoice. * Create and Confirm Credit Note. * Register a payment for the credit note. 6. Go back to subscription Observation: ------------------------------ The subscription is automatically set back to `In Progress` even though it was previously churned. Issue: ------------------------------ The method `_reopen_paid_churned_subscription` reopens churned subscriptions when an invoice is set to `in_payment` or `paid`. There was no check to exclude refund moves (`move_type = 'out_refund'`), causing the subscription to be reopened when a credit note is paid. Solution: ------------------------------ Add a condition to exclude refund invoices from the reopening logic opw-5947999
This pull request fixes a technical error in the Point of Sale module that was preventing the system from functioning correctly. The issue stemmed from an incorrect number of arguments being passed to a function, which has now been corrected. This ensures the Point of Sale functionality continues to operate smoothly.
Original PR description
`IrModuleModule._load_pos_data_fields() takes 1 positional argument but 2 were given` `File \"/opt/odoo/auto/addons/point_of_sale/models/pos_session.py\", line 185, in load_data\n 'fields': self.env[model]._load_pos_data_fields(response['pos.config']['data'][0]['id']),\nTypeError: IrModuleModule._load_pos_data_fields() takes 1 positional argument but 2 were given\n",` @Tecnativa TT57146 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update prevents the system from incorrectly syncing ‘e-Cobranza’ documents as vendor bills in the Uruguayan localization. By aligning this process with how we handle other documents like ‘e-Remito’ and ‘e-Resguardos’, we ensure data consistency and accuracy for financial reporting.
Original PR description
This pull request improves the synchronization process of vendor bills within the Uruguayan localization (`l10n_uy_edi`). Currently, the system might fetch documents that are not technically bills during synchronization. With this change, the system will explicitly avoid synchronizing `e-Cobranza` (Collection notes or Receipts) documents as vendor bills. Reasoning: `e-Cobranza` documents function conceptually more like payment receipts rather than actual vendor bills. Pulling them into the system as bills creates inconsistencies. This update aligns the handling of `e-Cobranza` with the existing behavior for `e-Remito` (Delivery Guides) and `e-Resguardos` (Withholdings), which are also appropriately excluded from bill synchronization. **Related Tasks** LATAM Task: 1367 ADHOC Task: 58906
This update fixes an issue where imported task recurrence values were being overwritten with default settings. Now, when importing tasks with custom recurrence rules from spreadsheets, the system correctly applies those rules, ensuring data accuracy and consistent task scheduling. This prevents users from needing to manually adjust recurrence settings after import.
Original PR description
### Steps to reproduce: - Create a xlsx sheet with some fsm_tasks values with recurrence values - Import the sheet to Field Service > Tasks - Navigate to the created tasks - Notice the recurrence values is the default ones not the ones in the imported sheet ### Cause: If we are importing records without recurrence_id value we will set the recurrence fields' values to the default values while we might already have values for those fields ### Fix: Check if we have values for recurrence fields we don't set the defaults and let the create method create the project.task.recurrence record and set the recurrence_id opw-5925546
This update addresses a visual issue where blank space appeared in activity cards after a description was cleared. The fix prevents the UI from rendering empty notes when the activity description is empty, resulting in a cleaner and more professional user experience. This improves the overall appearance of activity cards.
Original PR description
**Description of the issue/feature this PR addresses:** When an activity description is cleared, the stored value may still contain empty HTML content. The UI was still rendering this as a note,…
**Description of the issue/feature this PR addresses:** When an activity description is cleared, the stored value may still contain empty HTML content. The UI was still rendering this as a note, resulting in unnecessary blank space in the activity card. **Current behavior before PR:** Even when the activity description is cleared and contains only empty HTML, the activity note container is still rendered, leaving visible empty space in the UI. **Desired behavior after PR is merged:** The activity note is rendered only when it contains meaningful content. Empty HTML descriptions are ignored, preventing blank space from appearing in the activity card UI. Before <img width="445" height="84" alt="image" src="https://github.com/user-attachments/assets/f6648bb0-78d9-4063-a347-fe664370106e" /> After <img width="459" height="72" alt="image" src="https://github.com/user-attachments/assets/84c2063a-7c68-4dfe-b729-566ca4b5dcd1" /> task-[4752613](https://www.odoo.com/odoo/project/1519/tasks/4752613) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update fixes a potential issue where automated email services (Mail Defender) could inadvertently cancel or reschedule appointments due to clicking links in emails. The system now uses a form instead of a direct link, preventing these actions and ensuring appointments are handled correctly. This improves appointment scheduling reliability.
Original PR description
…ointments Mail defender services may click URLs in emails to verify their contents. Additionally they may sometimes interact with the page and visit related pages. For this reason URLs sent in emails should not trigger any action directly nor contain any simple link that could trigger an action. The "cancel/reschedule" anchor URL is replaced with a form which bots should not click. We also port the fix done in appointment to the view in appointment as it replaces the original view in this module. task-4555579 Forward-Port-Of: odoo/enterprise#79831
This update resolves a technical issue related to how Odoo imports bank statements from CODA when multiple journals share the same IBAN but different currencies. The fix prevents a 'singleton error' by intelligently skipping unnecessary processing steps, ensuring accurate data import and avoiding potential disruptions to financial reporting.
Original PR description
When having multiple journals with the same IBAN, but different currencies, we could have a singleton error if they are not all configured the same (besides the currency). This happens in the cron that fetches new CODAs as we first fetch all CODAs. Then, for each, we have to dispatch it in the right journal. To do so, we rely on `_parse_bank_statement_file` which is called on `self`, which itself calls `_get_coda_final_statements` that triggers the singleton error. However, at this point, we don't care about calling `_get_coda_final_statements` since we only want to retrieve the IBAN and the currency of the CODA, we don't care about the other details. Thus, the solution here is to ignore this call if we don't need it while just retrieveing the necessary info to match a journal before even creating the statements. opw-5723017 opw-6036909
This update fixes a technical issue in the demo certificate used for Peru's electronic invoicing (PE) system. The original certificate's lifespan was shortened, causing testing problems. This change extends the certificate's validity by ten years, ensuring accurate demonstration and testing of the l10n_pe_edi module.
Original PR description
In runbot's faketime tests, the test 1 year in the future goes past the end date of the demo PE certificate which had a lifetime of 2017-02-25 to 2027-02-25. This commit replaces that with one that lasts another ten years (2026-03-13 to 2036-03-13). runbot-241058 Forward-Port-Of: odoo/enterprise#110719
This update resolves an issue where CFDI reports incorrectly displayed '99 - False' instead of '99 - Por definir' for invoices using payment method 99. The fix ensures that the correct payment method description is now shown on the generated reports, improving data accuracy for Mexican tax reporting.
Original PR description
**PROBLEM** PR https://github.com/odoo/enterprise/commit/843d57b25f925a5d4f1848b85717adb4d1a9d388 Archives payment method 99, but because it's archived `_l10n_mx_edi_get_extra_invoice_report_values()` doesn't retrieve it. This leads the pdf report to display '99 - False' instead of '99 - Por definir'. **STEP TO REPRODUCE** 1. Create an invoice with the mx company. 2. Set the due date sometime in the month later. (To have the PPD payment policy on the invoice). 3. Send and generate the invoice using cfdi. opw-5927655 Forward-Port-Of: odoo/enterprise#107267
This update corrects a problem where accessing user fields after uninstalling the Auth-OAuth module caused errors. The fix ensures that user fields are properly removed from a shared list, preventing conflicts and crashes, especially in multi-tenant environments. This improves stability and prevents unexpected application behavior.
Original PR description
At install, the `auth_oauth` module adds `oauth_access_token` to the constant list `base.models.res_users.USER_PRIVATE_FIELDS`. At uninstall, it doesn't get removed automatically, it stays in the…
At install, the `auth_oauth` module adds `oauth_access_token`
to the constant list `base.models.res_users.USER_PRIVATE_FIELDS`.
At uninstall, it doesn't get removed automatically,
it stays in the list until a server restart or a worker
reload.
This causes problem when other/custom modules also add fields
to this `USER_PRIVATE_FIELDS` and then perform a read
with one of these private fields.
in `odoo/addons/base/models/res_users.py` in the method `def _fetch_query`
`self.env.cache.update(records, self._fields[fname], repeat('********'))`
raises a crash as it tries to access `self._fields['oauth_access_token']`
while it no longer exist.
Actually it's also a multi-tenant problem: If one database installs the
`auth_oauth` module on the server, `oauth_access_token` is added to the list
`USER_PRIVATE_FIELDS` for all databases, not just the one which installed
the `auth_oauth` module.
The solution is to convert this list with a property method,
and override that property method in `auth_oauth` to add
`oauth_access_token` when the module is installed.
It also solves the multi-tenant issue.
Steps to reproduce:
- Use this diff to add temporary a private field
```diff
diff --git a/odoo/addons/base/models/res_users.py b/odoo/addons/base/models/res_users.py
index 2c8da7ec529c..ac973205e6ef 100644
--- a/odoo/addons/base/models/res_users.py
+++ b/odoo/addons/base/models/res_users.py
@@ -87,7 +87,7 @@ class CryptContext:
# Only users who can modify the user (incl. the user herself) see the real contents of these fields
-USER_PRIVATE_FIELDS = []
+USER_PRIVATE_FIELDS = ['login']
MIN_ROUNDS = 600_000
concat = chain.from_iterable
```
- Start the server, preferably in threaded mode rather than worker mode
- Then, in the web interface, install and uninstall `auth_oauth`
- Then, using RPC, do a read on `res.users` with `login` as field
```py
import xmlrpc.client
URL, DB, UID, PASSWORD = 'http://localhost:8069', '17.0', 6, 'demo'
models = xmlrpc.client.ServerProxy('{}/xmlrpc/2/object'.format(URL))
print(models.execute_kw(DB, UID, PASSWORD, 'res.users', 'read', [[1], ['login']]))
```
```
Traceback (most recent call last):
File "/home/odoo/src/odoo/17.0/odoo/http.py", line 2410, in __call__
response = request._serve_db()
File "/home/odoo/src/odoo/17.0/odoo/http.py", line 1985, in _serve_db
return service_model.retrying(self._serve_ir_http, self.env)
File "/home/odoo/src/odoo/17.0/odoo/service/model.py", line 153, in retrying
result = func()
File "/home/odoo/src/odoo/17.0/odoo/http.py", line 2013, in _serve_ir_http
response = self.dispatcher.dispatch(rule.endpoint, args)
File "/home/odoo/src/odoo/17.0/odoo/http.py", line 2217, in dispatch
result = self.request.registry['ir.http']._dispatch(endpoint)
File "/home/odoo/src/odoo/17.0/odoo/addons/base/models/ir_http.py", line 221, in _dispatch
result = endpoint(**request.params)
File "/home/odoo/src/odoo/17.0/odoo/http.py", line 799, in route_wrapper
result = endpoint(self, *args, **params_ok)
File "/home/odoo/src/odoo/17.0/addons/web/controllers/dataset.py", line 25, in call_kw
return self._call_kw(model, method, args, kwargs)
File "/home/odoo/src/odoo/17.0/addons/web/controllers/dataset.py", line 21, in _call_kw
return call_kw(Model, method, args, kwargs)
File "/home/odoo/src/odoo/17.0/odoo/api.py", line 484, in call_kw
result = _call_kw_multi(method, model, args, kwargs)
File "/home/odoo/src/odoo/17.0/odoo/api.py", line 469, in _call_kw_multi
result = method(recs, *args, **kwargs)
File "/home/odoo/src/odoo/17.0/odoo/addons/base/models/res_users.py", line 1913, in read
res = super(UsersView, self).read(other_fields, load=load)
File "/home/odoo/src/odoo/17.0/odoo/addons/base/models/res_users.py", line 645, in read
return super(Users, self).read(fields=fields, load=load)
File "/home/odoo/src/odoo/17.0/odoo/models.py", line 3583, in read
self._origin.fetch(fields)
File "/home/odoo/src/odoo/17.0/odoo/models.py", line 3874, in fetch
fetched = self._fetch_query(query, fields_to_fetch)
File "/home/odoo/src/odoo/17.0/odoo/addons/base/models/res_users.py", line 551, in _fetch_query
self.env.cache.update(records, self._fields[fname], repeat('********'))
KeyError: 'oauth_access_token'
```
opw-6042456
Forward-Port-Of: odoo/odoo#254387This update fixes a potential issue where Odoo activities could incorrectly report 'no record found' errors. The change ensures that the system verifies the existence of related records before retrieving activity data, preventing these errors and improving stability. This primarily impacts activity creation and management workflows.
Original PR description
Browse method of orm only returns a recordset of ids provided but never checks if those ids actually exist, which when testing actvities can lead to no record found errors. This happens because the values /res_id might exist in mail_activity but not the related table. Co-Authored By: apan-odoo apan@odoo.com --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update resolves a bug where the default email template body wasn't loading correctly in the full composer view within the chatter. Now, the full composer always displays the intended default template body, ensuring consistent email communication. This improves the user experience and prevents blank emails.
Original PR description
**Issue:** - When opening the full composer from the chatter, the body of the default email template is not loaded. Only the subject line from the template appears, while the body remains empty or…
**Issue:** - When opening the full composer from the chatter, the body of the default email template is not loaded. Only the subject line from the template appears, while the body remains empty or contains only the user's signature. **Steps to reproduce:** 1. Install `contact` 2. Open any contact form. 3. In the chatter, click 'Send message' and then expand button 4. Write a something in body, then save this as a new template. 5. Set this new template as the default (using Debug Mode > Set Default Values). 6. Click 'Send message' in the chatter, 7. Click the 'Full composer' (expand) button without typing anything. **Observed behavior:** - The full composer opens with the correct subject from the default template, but the body is empty. **Cause:** - The `onClickFullComposer` method always passes a `default_body` value in the context to the mail.compose.message wizard. Even if the chatter input is empty **Solution:** - Forward isBodyEmpty in the context from onClickFullComposer. If the user typed content, do nothing. If the body is empty and a default template is available, allow the backend to apply the default template by removing default_body. opw-5405056
This update fixes an issue in the Odoo stock management system where reusable packaging was incorrectly assigned as the destination for certain moves. The change ensures that disposable packaging is handled correctly, aligning with how products are delivered. This improves the accuracy of stock tracking and fulfillment processes.
Original PR description
Commit https://github.com/odoo/odoo/commit/0358963e2088a309141f092fbe8f7a98786cc1d8 forces the `result_package_id` on the package level stock move lines (meaning move lines being part of entire package move) to be the source package. This makes sense when moving entire packs but not in case of delivery with disposable packages. We remove the line that set the destination package for any package type and keep the one doing this for disposable package only. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr