Wednesday, September 2, 2026
21 changes · saas-18.3
Enhancements to existing features
Businesses using third-party billing software in Ecuador can now record the provider's RUC in invoicing settings. The value is automatically included in electronic documents, printed reports, and delivery guides to help meet SRI reporting requirements.
Original PR description
Purpose: SRI Resolution requires taxpayers using 3rd-party billing software in Ecuador to report the software provider's RUC on all electronic documents and printed representations (RIDE). A new system parameter is introduced and displayed in Invoicing > Setting > Ecuadorian Localization > Electronic Invoicing, so users can add their software provider's RUC. This value will be automatically sent to the EDI and displayed on the report. task-6432810 Forward-Port-Of: odoo/enterprise#129456
Resolved issues and error corrections
A rental pricing test was made independent of the time of day so it no longer fails late in the UTC day. This improves reliability of automated checks without changing customer-facing rental pricing behavior.
Original PR description
Scenario:
- be (or switch your computer) at time between 21:01 and 23:59 UTC
- run test test_product_attribute_value_config_get_combination_info
Result:
This error is happening:
Traceback (most recent call last):
File "…/tests/test_website_sale_product_attribute_value_config.py",
line 106, in test_product_attribute_value_config_get_combination_info
self.assertEqual(combination_info['price'], price_3_hours)
AssertionError: 6.42 != 15.0
Cause: since the time range is on multiple day, we favor a weekly price
that is more interesting and the result is not the 3 hours price.
Fix: set the date for the test.
runbot-227695Code cleanup and technical improvements
The Factur-X electronic invoice export has been reworked to use a more structured generation process instead of template-based XML creation. This is an internal change that should make future maintenance and format updates easier while preserving existing invoice exchange behavior.
Original PR description
*= account_edi_ubl_cii_tax_extension, l10n_account_edi_ubl_cii_tests. Refactoring of the export of factur-x. The export now relies on a dict of nodes, and uses the function `dict_to_xml` to generate the xml instead of relying on a qweb template. task-5999127 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#261572
The system now handles requests with URLs that are too long without triggering an additional server error. This keeps the proper error response intact and improves reliability when unusual or malformed requests reach the server.
Original PR description
- When the request URI is too long, the HTTP server rejects the request before parsing the headers. As a result, `self.headers` is not available when the WebSocket compatibility code in `send_header()` and `end_headers()` is executed. - Access `self.headers` safely to avoid an AttributeError while handling the 414 response. **opw-6501275** --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285870
An outdated Point of Sale data cleanup step was removed because a newer, more targeted fix now handles the issue more safely. This reduces the risk of removing valid order information while still clearing only obsolete loyalty reward lines when needed.
Original PR description
This fix is no longer required(https://github.com/odoo/odoo/pull/202752) as this one (https://github.com/odoo/odoo/pull/257043) is cleaner and less aggressive (it will only delete stale reward lines). This is the relevant part of the new fix to delete the previous one: https://github.com/odoo/odoo/pull/257043/changes#diff-18cef42f8c39513a82387e9cb81bc732b252304cd15b5b2f7b0b4623ac20cb41R100-R104 opw-6447092 Forward-Port-Of: odoo/odoo#285376
Fixed an issue where automated activity creation could cause new time off requests to show 0 days or 0 hours. The system now recalculates the duration after the request dates are finalized, so approvals and balances reflect the actual requested time.
Original PR description
Current behavior: -- With an active automation rule (base_automation) whose action creates an activity (e.g. a "Time Off Approval" activity) on hr.leave creation, every newly created time off request…
Current behavior: -- With an active automation rule (base_automation) whose action creates an activity (e.g. a "Time Off Approval" activity) on hr.leave creation, every newly created time off request has a duration of 0 days / 0 hours, regardless of the requested dates. Expected behavior: -- The leave duration is computed from the requested dates, unaffected by the presence of an activity-creating automation rule. Steps to reproduce: -- - Create an automation rule on hr.leave, trigger "On Creation & Update". - Add an action that creates an activity (type "Time Off Approval"). - Create any time off request for an employee with a working schedule. - The request shows a duration of "0 days" (or "0 hours"). Cause of the issue: -- When an automation with a "Create Activity" action runs on leave creation, base_automation schedules the activity after the record is created. Creating the activity reads the leave record, forcing an early flush of its pending computes. At that point date_from/date_to are not yet settled, so the duration compute (number_of_days/number_of_hours) reads empty dates and stores (0, 0). As these are stored fields, they are marked done and never recompute. Fix: -- In create(), after the record is created and its dates are settled, recompute the duration explicitly so any zero stored by an early flush is overwritten with the correct value. opw-6235902 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284373
Remaining hours on sales order lines for timesheet-based services now update when the unit of measure or availability settings change. This helps teams see more reliable remaining work estimates without needing manual refreshes or corrections.
Original PR description
The dependencies of _compute_remaining_hours do not match the fields actually used for the computation: it lists analytic_line_ids, which it never uses, and omits both remaining_hours_available, and product_uom. _compute_remaining_hours_available has the same issue: it uses product_uom but only depends on product_id.service_policy. analytic_line_ids, on the other hand, can be dropped: qty_delivered already depends on it, along with its so_line, unit_amount, product_uom_id and project_id, so the timesheet flow keeps triggering the recomputation. This PR fixes the dependencies for both aforementioned compute methods. Task-4748521 Forward-Port-Of: odoo/odoo#285418 Forward-Port-Of: odoo/odoo#284750
This update fixes an inconsistent automated test for Canadian payment file handling by ensuring items are checked in a consistent order. It helps keep validation reliable and reduces false failures in the release process, with no expected change for end users.
Original PR description
Sorts the expected items in `test_cpa005` to ensure consistent ordering. runbot error: https://runbot.odoo.com/odoo/error/941567
Assignees will now receive notifications when recurring project tasks are automatically created, matching the behavior of manually assigned tasks. This helps teams avoid missed work caused by silent recurring task assignments while keeping normal task duplication quiet.
Original PR description
Before this commit, assignees of an automatically created recurring task occurrence never receive an assignment notification, unlike a manually assigned task. Steps to reproduce: 1. Enable recurring…
Before this commit, assignees of an automatically created recurring task occurrence never receive an assignment notification, unlike a manually assigned task. Steps to reproduce: 1. Enable recurring tasks, create a task, assign it to user B, and set it to repeat (e.g. daily). 2. As user A, mark the task done so the next occurrence is created. 3. User B never gets an assignment notification for the new occurrence, even though they would if user A had assigned them manually. This happens because `_create_next_occurrence()` creates the next task via `ProjectTask.copy()`. `copy()` sets `mail_auto_subscribe_no_notify=True` in its context to avoid spamming followers when a task is duplicated (e.g. the "Duplicate" button), but recurrence reuses that same `copy()` and inherits the suppression, so assignees of auto-created occurrences are silently skipped. This commit fixes the issue by explicitly calling `_task_message_auto_subscribe_notify()` after copying the new task, with `mail_auto_subscribe_no_notify` reset to `False`. Thanks to this, assignees get notified like any other assignment, while normal manual copies keep their existing silent behaviour. Forward-Port-Of: odoo/odoo#282651
This fix prevents failed status updates when the French e-invoicing service returns a response that cannot be tracked. Businesses using French PDP e-invoicing avoid blocked scheduled processing and related error messages after vendor bill cancellations.
Original PR description
Steps to reproduce: - Install `l10n_fr_pdp` and `l10n_be` module - Activate `French e-invoicing` (you need to put your DB in test mode) (i.e: `account_peppol.edi.mode = 'test'` in system parameter)…
Steps to reproduce:
- Install `l10n_fr_pdp` and `l10n_be` module
- Activate `French e-invoicing` (you need to put your DB in test mode)
(i.e: `account_peppol.edi.mode = 'test'` in system parameter) Refer this Documentation https://www.odoo.com/documentation/19.0/applications/finance/fiscal_localizations/france.html?highlight=e%20invoicing#localizations-france-e-invoicing-fac-elec-config
- Create a Invoice and Sent with `E-invoicing`
- Run `PEPPOL: retrieve new documents` Cron
- In Invoice Other Info > `E-Invoicing Status` should be in `Done` state
- Now Vendor Bill is created for that invoice > Cancel that bill with reason > Check `E-Invoicing Status` response for bill(one response will be without UUID)
- Go to schedule actions > `PEPPOL: update message status`
- Run it and get the traceback: `KeyError: 'false'`
Issue:
When sending a lifecycle response to the French PDP, `_pdp_send_response` calls the `/api/pdp/1/send_response` endpoint and expects IAP to return a `message_uuid` for each response.
However, IAP return a response without a message UUID, for example: ` {'messages': [{'message_uuid': False}]}` `_pdp_send_response` currently assumes that every returned message has a valid UUID and creates an `account.peppol.response` with:
```
'peppol_message_uuid': False
'peppol_state': 'processing'
```
This leaves an `account.peppol.response` in `processing` state without a UUID that can be used to track it.
During the next execution of `_cron_peppol_get_message_status`, `_peppol_get_message_status` retrieves this response through `_peppol_get_documents_for_status` and builds `uuid_to_record` using `peppol_message_uuid` as the key. The resulting mapping contains the Python value `False` as a key.
The cron then calls the PDP `1/get_document` endpoint with this invalid UUID. IAP returns it as the string `'false'`, which is passed to `_peppol_process_messages_status`. The French PDP implementation tries to retrieve the corresponding record with: `uuid_to_record[uid]`
Since the mapping contains `False` while `uid` is `'false'`, this raises: `KeyError: 'false'`
This failure prevents the status cron from completing the processing of the messages.
Solution:
Avoid creating the `account.peppol.response` when IAP does not return a `message_uuid`. A response without a UUID cannot be tracked through the PDP status flow, so creating it in `processing` state only leaves an
invalid record that will later cause the status processing to fail.
opw-6453133
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#281691Fixed an issue where time off requests could show 0 days or 0 hours when an automated rule created an approval activity. Durations are now recalculated after the request dates are finalized, so employees and managers see the correct leave length.
Original PR description
Current behavior: -- With an active automation rule (base_automation) whose action creates an activity (e.g. a "Time Off Approval" activity) on hr.leave creation, every newly created time off request…
Current behavior: -- With an active automation rule (base_automation) whose action creates an activity (e.g. a "Time Off Approval" activity) on hr.leave creation, every newly created time off request has a duration of 0 days / 0 hours, regardless of the requested dates. Expected behavior: -- The leave duration is computed from the requested dates, unaffected by the presence of an activity-creating automation rule. Steps to reproduce: -- - Create an automation rule on hr.leave, trigger "On Creation & Update". - Add an action that creates an activity (type "Time Off Approval"). - Create any time off request for an employee with a working schedule. - The request shows a duration of "0 days" (or "0 hours"). Cause of the issue: -- When an automation set to create and update is used to create a time-off approval activity, the code for the computation of the date_from and date_to fields are run. However, in side this code is the _display_warning_error function which contains a call to compute the number_of_days and number_of_hours fields. These fields rely on the values of date_to and date_from, causing them to retrieve values that are not yet computed, which are (0,0). Fix: -- Once date_from/date_to are settled at the end of _compute_date_from_to, add the duration fields (number_of_days, number_of_hours, duration_display) back to the compute queue so they are recomputed against the correct dates. opw-6321257 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Refunds using the demo payment provider now work properly after a manually captured payment. This prevents users from getting stuck with an incorrect negative authorized amount and unable to complete the refund process.
Original PR description
Issue: --- When using manual capture, you can refund the transaction but it will be only authorized, and you'll then be blocked with a negative authorized amount and the impossibility to refund it. This seems to be specific to demo payment provider. Steps: 1- Enable manual capture on demo provider. 2- Buy a product from shop and checkout and pay. 3- Capture the payment in backend. Then click on post process. 4- Try refund. opw-6413515 Forward-Port-Of: odoo/odoo#282315
This fix keeps the Android camera workaround only for Chrome-based Android browsers that need it. It avoids showing inappropriate file options in other environments, such as the Odoo mobile app, while preserving camera access for affected users.
Original PR description
Since Android 14, Chromium sends a file input accepting only images straight to the photo picker, which has no "Camera" entry. The image fields work around it by appending `dummy/allowAndroidCamera`…
Since Android 14, Chromium sends a file input accepting only images straight to the photo picker, which has no "Camera" entry. The image fields work around it by appending `dummy/allowAndroidCamera` to their accept attribute: a mimetype which is not an image is enough to get the generic chooser, and its camera, back. https://issues.chromium.org/issues/40937303 That invalid mimetype was appended for everyone, while only the browsers based on Chromium on Android need it: - the issue is an Android one, the desktop file dialogs are not concerned - the native app builds its own file chooser out of the accept attribute, and the invalid mimetype makes it offer the document picker on a field which only accepts images - Firefox and Safari are not based on Chromium and are not affected The workaround is now limited to the browsers needing it, and the expression moved from the template to a getter, since it is no longer a simple concatenation. Code made by Claude Supervised by RFR --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285969 Forward-Port-Of: odoo/odoo#285643
When adding a certificate key file, users will no longer see an error banner simply because they left the password field empty. The warning now appears only when an entered password is incorrect, reducing confusion during certificate setup.
Original PR description
When adding a key file without entering a password, an error banner is immediately displayed, incorrectly suggesting that the password may be invalid. Only show the error banner when a password was provided and is incorrect. Also refactored the compute function to avoid repeated try-except blocks. task-6299175 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283589
The helpdesk team card now displays the mail alias in line with the team name. This small visual correction makes the Helpdesk settings page look cleaner and easier to scan.
Original PR description
In this commit, we remove the margin before the mail alias, ensuring aligment within the helpdesk team card. task-6416578 Forward-Port-Of: odoo/enterprise#129865
This fix makes Point of Sale testing more reliable when demo databases contain many customers. The automated tour now searches for additional results before selecting a customer, preventing false failures in environments with larger demo data sets.
Original PR description
When running with demo data with many modules installed, there can be enough partners in the DB that the partner search in POS does not find the partner straight away, and requires another batch to be loaded. In this case, a tour that tries to select the partner straight away will fail. This commit fixes the issue by always pressing enter to search more in a tour when selecting a partner. The required tour steps were already present, just not always used, so they have been extracted into a function. runbot-233397 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Cancelled point-of-sale orders and order lines are now saved and marked as cancellations when sent for German fiscal certification. This helps ensure Fiskaly receives the correct information, improving compliance and reducing the risk of incorrect fiscal records.
Original PR description
In this commit: --------------- - We now store cancelled retail orders on the server and send the `storno` flag as `true` for cancelled lines and orders to ensure proper handling in Fiskaly. task: 6326042 Relataed PR: https://github.com/odoo/odoo/pull/277648 Forward-Port-Of: odoo/enterprise#120410
This fixes an issue where Indian e-waybill stock screens could break in certain single-app test setups because a required stock accounting component was not explicitly included. Adding the dependency makes the setup more reliable without changing everyday user workflows.
Original PR description
The view 'l10n_in_ewaybill_stock.view_picking_form_inherit_ewaybill' is broken in single-app tests because it depends on stock.picking:country_code. That field is provided by module 'stock_account' through auto_install relationship. 'stock_account' auto_installs with 'stock' and 'account' installed. This condition exists on stable so it's safe to add this dependency. The dependency is added to l10n_in_stock because it seemed like the logical place where 'account' and 'stock' functionality comes together. [l10n_in_ewaybill_stock] ──[depends]──> [l10n_in_stock] [l10n_in_stock] ──[depends]──> [stock] [l10n_in_stock] ──[depends]──> [l10n_in] ──[depends]──> [account_tax_python] ──[depends]──> [account] REF Runbot: https://runbot.odoo.com/odoo/error/945482 Forward-Port-Of: odoo/odoo#284990
This fixes a configuration omission so the Greek electronic invoicing module is included in the translation workflow. It helps ensure the module can receive and maintain translated text for users in supported languages.
Original PR description
Commit https://github.com/odoo/odoo/commit/45bd522dde7a67194e14a40d66944a2e34d1f79d introudced a new module without it's related `weblate.json` entry. This commit fixes this omission. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285570
This fixes an issue where manually increasing the billed quantity on a timesheet invoice could prevent later timesheet entries from being invoiced. Businesses can now continue billing future periods correctly, while refund-related behavior remains protected.
Original PR description
## Issue When a use rmanually increases the invoiced quantity on a timesheet invoice, subsequent timesheets logged in future periods can no longer be invoiced. The system assumes that the most recent…
## Issue
When a use rmanually increases the invoiced quantity on a timesheet invoice, subsequent timesheets logged in future periods can no longer be invoiced. The system assumes that the most recent logged hours are already covered by the previously over-invoiced amount, blocking the billing of the most recent timesheet entries.
## Steps to reproduce
1. Install *Sales Timesheet* (`sale_timesheet`)
2. Create a Product P
- Product Type: Service
- Invoicing Policy: Based on Timesheets
- Create on Order: (Project &) Task
3. Create an SO:
- Customer: Any
- Product: P (any quantity)
- Confirm
4. Record hours on the task created:
- 06/01/2026 (June 1st): 1 hour
- 07/01/2026 (July 1st): 1 hour
5. Create the invoice for the June timesheet entry (by setting a timesheets period when creating the invoice), then **change the quantity to any value strictly greater than 2** and confirm.
6. Create the invoice for July
7. **An "Invalid Operation" error appears, stating that there's nothing to invoice, even though the timesheet entry from July was never invoiced.**
## Cause
Since https://github.com/odoo/odoo/commit/3b86ac3d180993239b63fd305ee0ba1f17f7eb20, the computation of the quantity to invoice changed to include the difference between the quantity delivered and the quantity already invoiced. In the flow described by the steps to reproduce above, the quantity to invoice is larger than the quantity delivered, making the `qty_to_invoice` equal to `0.0`.
https://github.com/odoo/odoo/blob/626d31fa0191bfe7ca8e1fcf177357eeeb60f2c7/addons/sale_timesheet/models/sale_order.py#L331-L334
The reason for the fix above being the partial refunding of timesheet-related invoices, we can keep that solution when working with refunded invoices, and keep the previous behavior for other cases.
This solution solves the issue in the steps to reproduce above, but was also manually tested on the issues from https://github.com/odoo/odoo/commit/3b86ac3d180993239b63fd305ee0ba1f17f7eb20 and https://github.com/odoo/odoo/commit/64cf4afabd0c5ef040cf87fc6f3125fe0bb81bbb.
opw-6485674
Forward-Port-Of: odoo/odoo#286043
Forward-Port-Of: odoo/odoo#284470Fixed an issue where an employee shown on multiple Planning Gantt rows could have some rows incorrectly greyed out as if they were unavailable. Working hours are now applied consistently across all rows for the same employee, making schedules easier to read and reducing confusion when grouped by project or resource.
Original PR description
Issue: ---------------------------------------- In the Planning Gantt view, when an employee's slots are split across several rows, all of them are greyed out except the last one, which correctly…
Issue: ---------------------------------------- In the Planning Gantt view, when an employee's slots are split across several rows, all of them are greyed out except the last one, which correctly displays the employee's working hours. Steps to reproduce: ---------------------------------------- - Have an employee with a running contract. - Create two shifts for that employee on two different projects. - Open Planning, switch to the Gantt view, and group by Resource, then by Project. - Only one of the two rows for that employee shows the working hours; the other is greyed out. Cause: ---------------------------------------- The grey background is applied by the Gantt view to any cell that has no matching working period, the same way it greys out days off. The working periods, based on the employee's work intervals are computed in `gantt_resource_employees_working_periods()` and indexed by employee id in a plain dict (`row_per_employee_id`). When the same employee appeared in several rows, each new row overwrote the previous one in the dict, so only the last row kept a reference and got its working periods filled in. Solution: ---------------------------------------- Group the rows per employee into a list instead of a single dict entry, and append the computed `working_periods` to every row belonging to that employee. opw-6449130 Forward-Port-Of: odoo/enterprise#128094