Wednesday, September 2, 2026
9 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
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
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
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 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