Daily updates from Odoo
Monday, July 6, 2026
376 changes
29 changes
Enhancements to existing features
The timesheet timer now opens with the project the employee has most recently and consistently used, making repeat time entry faster. If the user is already viewing a specific active project or task, that context still takes priority, while archived or template records are no longer suggested.
Original PR description
When opening the timesheet systray, the timer is now prefilled with the project to which the employee's three most recent timesheets are all linked, since they are most likely to keep logging time on it. The currently viewed project or task takes precedence over the favorite project, and viewing a project form now prefills the timer as well, just like task views already do. task-6290859 Forward-Port-Of: odoo/enterprise#120028
The payroll data update process is now configured for the Philippines payroll module. This helps keep standard, non-customized salary rules automatically up to date, reducing manual maintenance and improving reliability for payroll users.
Original PR description
Currently, the "Payroll: Update data" cron doesn't work for HK payroll as we never set up the _get_data_files_to_update. We can set up the list of data files to keep up to date to better support our users by automatically keeping non-edited salary rules up to date. task-6360470
Budget reports now use the same profitability basis as analytic profitability views when selecting analytic accounting entries. This helps finance teams see more consistent budget figures across reports and profitability analysis.
Original PR description
Use the new field analytic_profitability in the conditions of the query to get the account analytic lines of the budget report task-4959636 Forward-Port-Of: odoo/enterprise#121898 Forward-Port-Of: odoo/enterprise#121760
Resolved issues and error corrections
This fix prevents small rounding differences in attendance overtime calculations from creating overlapping work entries. It helps keep employee work entry records accurate, especially for overnight shifts, reducing payroll or attendance inconsistencies.
Original PR description
__Issue:__ `duration` is rounded to 3 decimals (~1.8s drift) while `time_stop` is exact, so the back-projected start could land before midnight on overnight overtime or middle of the day causing overlaps with the previous line Example: - time_start = 03/05 00:00:00 - time_stop = 03/05 07:07:14 actual duration 7h07m14s gets stored as `duration = 7.121` (= 7h07m15.6s) after `round(_, 3)`. Back-projection yields `datetime_start = 07:07:14 - 7.121h = 02/05 23:59:58`, overlapping by ~2s with the prior line ending at `02/05 23:59:59.999`. __Fix:__ Sort lines by `time_stop` within each date and clamp `datetime_start` to the previously emitted interval's stop when the two intervals genuinely intersect. opw-6170828 Forward-Port-Of: odoo/enterprise#121564 Forward-Port-Of: odoo/enterprise#116565
Users can now preview canceled subscription orders without encountering an error. Canceled subscriptions are shown using the standard sales order preview instead of the subscription-specific portal view, preventing failed previews and improving reliability.
Original PR description
Currently, an error occurs when a user previews a canceled subscription order. **Steps to Reproduce:** - Install `sale_subscription` module. - Go to `Subscriptions` and create a `subscription order`…
Currently, an error occurs when a user previews a canceled subscription order.
**Steps to Reproduce:**
- Install `sale_subscription` module.
- Go to `Subscriptions` and create a `subscription order` with:
- a `subscription product`,
- a `recurring plan`,
- an `Until` (end date) value.
- `Cancel` the subscription order.
- Click `Preview`.
`TypeError: unsupported operand type(s) for +: 'bool' and 'relativedelta'`
When previewing a subscription order, the portal view is rendered. During rendering, the
subscription portal template is used, which computes tax values and requires calculating the
next invoice date based on the recurring plan's billing period. However, for canceled
subscription orders, next_invoice_date is False because it is only set when the order is in
the sale state. As a result, an error is raised [2].
This commit ensures that only subscription orders in the sale state use the subscription
portal template. Canceled subscription orders use the default sale order preview, similar
to orders in the draft and sent states. This is appropriate because canceled subscriptions
are not correctly displayed in the subscription portal, and they should not attempt to
render the subscription-specific portal view.
[1]- https://github.com/odoo/enterprise/blob/f833154b61fdb73c24d99462815a55313212b909/sale_subscription/controllers/portal.py#L686-L687
[2]- https://github.com/odoo/enterprise/blob/f833154b61fdb73c24d99462815a55313212b909/sale_subscription/models/sale_order.py#L2172-L2175
sentry-7579114635
Forward-Port-Of: odoo/enterprise#122287Refunded point of sale orders that fully cancel out matching customer-account payments are now hidden from the Settle Orders list. This keeps the list focused on amounts that still need action and avoids asking users to manually settle orders and refunds that already balance each other.
Original PR description
Currently, if you refund an order made on the customer account with the customer account as well, you can still see the order in the list of orders to settle. Steps to reproduce: -------------------…
Currently, if you refund an order made on the customer account with the customer account as well, you can still see the order in the list of orders to settle. Steps to reproduce: ------------------- * Open shop * Make an order using the customer account for a customer, don't invoice it * Refund one of the order using the customer account, don't invoice it * Make a new order using the customer account * In the customer list, find the customer used and select "Settle Orders" > The 2 orders are present in the list Why the fix: ------------ Originally the list would only show the orders for chich the customers have due (>0). https://github.com/odoo/enterprise/commit/bf4b6043b999b4a081b1afa73fc4113bf4db28f8 But recently the code we also see the refunds in the list as well. https://github.com/odoo/enterprise/commit/12af23d5382e972facfaa999e4c5ab30c97e8d1f However this new behavior is not visible if, with the refund, the customer account temporarily falls to 0. So currently we have some refunds that impact the amount to settle and some that don't. Originally we were thinking that either we should show all refunds in that list (given they use the customer account) or we shouldn't show any as it was previously. Both solutions are not ideal. * Showing them all would get the list bigger than it is and would require the customer to select the order and its refund(s) and settle them together. Since refunds are not usually done right after the order they would not be close it that list. However this solution would enable the option to remove the orders from the list requiring a few step from the customer. * Showing none isn't idea either with this use case as it means that we still see orders that were cancelled out by their refunds. To remove to order the customer has two options. Either going backend and searching the order and its refund(s) and invoice them, either settling the order but that means that now there's money deposited on the customer account. Any of the two option isn't perfect a it still requires manual intervention from the customer and wouldn't work on previous data. Creating a server action to correct those data wouldn't have been feasible either. Instead, the approach we're taking is the following: When loading the list of order to settle we want to remove the orders and the potential refunds were the customer account is evened out. We only need to look at the orders of the partners that contains refunds for which the customer account was used. If the sum of the transactions made on the customer account is 0 we can say that the order and its refunds have cancelled out each other (in terms of customer account) and we don't show them if the list of orders remaining to settle. opw-6170830 Forward-Port-Of: odoo/enterprise#117725
The Timesheets app now correctly marks days as unavailable in an employee's own timesheet when their working schedule changes. This helps users avoid entering time on days they are not scheduled to work.
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#122936 Forward-Port-Of: odoo/enterprise#113984
This fix prevents Belgian payroll processing from failing when an employee has multiple contract or employment versions within the same month. Payroll teams can complete pay runs for affected employees without manual intervention or blocked payslip generation.
Original PR description
Currently, there is an error while running payrun step with employee who has multiple version in 1 month. ``` number_of_hours = (work100_wds - worked_day).number_of_hours ValueError: Expected singleton: hr.payslip.worked_days(233, 234) ``` Step to reproduce: 1. Create Employee with multiple version in 1 month 2. Create New PayRun during that month 3. Run the PayRun until Payslip step 4. Expected error on payslip steps reason: substraction of work100_wds and worked_day generate more than 1 value, if we have multiple version in 1 month task-6296276 Forward-Port-Of: odoo/enterprise#122483
Sick leave taken without a certificate now correctly grants loss-on-commission compensation when it applies. This helps Belgian payroll calculations reflect the employee's entitlement more accurately and avoids underpayment in relevant cases.
Original PR description
Sick time off without certificate should grant loss on commissions if relevant Forward-Port-Of: odoo/enterprise#122807
Commission plans now prevent adding a salesperson whose start date falls after the plan's end date. This helps keep commission eligibility periods consistent and avoids invalid sales compensation records.
Original PR description
Version: 18.0 Steps to reproduce: - open sale commission plans and create a new plan with an effective period - go to the salesperson tab and add a salesperson - set the salesperson from date after the plan end date issue: salesperson period start date was accepted even if it was set after the plan end date fix: added validation to raise an error when the salesperson start date falls outside the plan effective period task id: 6241188 Forward-Port-Of: odoo/enterprise#118289
The recruitment reports app now declares the reporting component it needs to show cohort views. This prevents installation failures in specific automated installation scenarios, helping deployments complete smoothly.
Original PR description
installing hr_recruitment_reports with the --ski-auto-install flag causes an error. The error happens because it does not explicitly depend on web_cohort while displaying a cohort view. task-6352888 runbot_error-237854 Forward-Port-Of: odoo/enterprise#122432
Scanning a package during barcode picking now correctly assigns it as the destination package, even if that package already contains other products elsewhere. This prevents an unnecessary error when extra products are not allowed, helping warehouse teams complete two-step delivery workflows without interruption.
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 Forward-Port-Of: odoo/enterprise#122782 Forward-Port-Of: odoo/enterprise#121789
Users who choose to handle notifications inside Odoo will now be notified in their inbox when a signature request they sent is completed. This prevents missed updates and helps teams track completed signing tasks without relying on email notifications.
Original PR description
## Issue When a user sets their notification to "Handle in Odoo" (`inbox`) and a sign requested is completed, they do not receive the expected notification. ## Steps to reproduce 1. Install *Sign*…
## Issue When a user sets their notification to "Handle in Odoo" (`inbox`) and a sign requested is completed, they do not receive the expected notification. ## Steps to reproduce 1. Install *Sign* (`sign`) 2. Sets the current user's notification preference to "Handle in Odoo" (`inbox`) 3. Create a sign request and send it to Marc Demo 4. As Marc Demo, sign the request 5. **The user who sent the sign request did not receive a notification to notify them that the request was signed.** ## Fix This is a partial backport of both https://github.com/odoo/enterprise/commit/463d6a2aae536356e6dee6b902f2e881dbc4fbda (saas-18.2) and a related fix https://github.com/odoo/enterprise/commit/41395dba4fd31222f5fd9fc94a84c977cf9334f9 (19.0). Before the first commit, users would not receive inbox notification when sign requests would be completed. ## Note to reviewer The issue only occurs in 18.0, as it is fixed by https://github.com/odoo/enterprise/commit/463d6a2aae536356e6dee6b902f2e881dbc4fbda in 18.2, but we can backport the fix from https://github.com/odoo/enterprise/commit/41395dba4fd31222f5fd9fc94a84c977cf9334f9 from 18.2 to 18.4 if desired. opw-6251702 Forward-Port-Of: odoo/enterprise#122740 Forward-Port-Of: odoo/enterprise#120740
Fixed an issue where the Ask AI button could fail when more than one default prompt was set up for the same AI agent and interface. The system now chooses the most relevant prompt automatically, keeping AI assistance available without requiring users to clean up duplicate configurations.
Original PR description
## Problem When multiple Default Prompts are configured for the same AI Agent and interface key, clicking the "Ask AI" button raises a ValueError. ## Cause The `_get_composer_from_key_and_model`…
## Problem When multiple Default Prompts are configured for the same AI Agent and interface key, clicking the "Ask AI" button raises a ValueError. ## Cause The `_get_composer_from_key_and_model` method searches for composers matching an interface_key and model, but doesn't limit the results. When multiple Default Prompts exist for the same agent, the search returns multiple records, causing a singleton error when accessing `ai_agent_id`. ## Steps to Reproduce [[Video](https://drive.google.com/file/d/1yMAmX4RuevS0vH07qex2V0fMAiLrtJBg/view?usp=sharing)] 1. Go to AI > Configuration > Default Prompts 2. Create a new Default Prompt with Odoo Agent 3. Click the Ask AI button in the top-right corner 4. Error: ValueError: Expected singleton: ai.agent(2, 1) ## Fix Replace the two-step search with a single search using an `OR` domain: - Search both model-specific and generic Default Prompts in one query. - Order the results with `focused_model_id desc` so model-specific prompts are preferred over generic ones. - Return only one record using `limit=1`. This preserves the previous behavior while preventing singleton errors. --- opw-6323764 Forward-Port-Of: odoo/enterprise#121609
Fixes an error that could occur when shortening the deadline of a standalone task in the Project Gantt chart. Users can now adjust task deadlines normally, even when the task has no dependent follow-up tasks.
Original PR description
## Current behavior: In the Project's app, switch to Gantt chart's view, when changing the deadline of a single task by shrinking its right edge, the server throws `ValueError: max() iterable…
## Current behavior: In the Project's app, switch to Gantt chart's view, when changing the deadline of a single task by shrinking its right edge, the server throws `ValueError: max() iterable argument`` is empty when calling end_date = max(candidates.mapped(stop_date_field_name)). ## Steps to reproduce: 1. In version 19.0 and above, install Project app 2. Create a project and only 1 single task 3. Switch to Gantt chart view 4. Try changing the deadline of a task by dragging its right edge 5. Observe that extending the task's deadline by dragging to the right works fine, but shrinking the deadline by dragging to the left will cause server to throw RPC_ERROR: Odoo Server Error and ValueError: max() iterable argument is empty. ## Cause of the issue: - A task with NO successors will cause candidates gathered via dependency_inverted_field_name to be empty. - The empty candidates recordset then get called by max(candidates.mapped(stop_date_field_name)), which is the reason causing error message ValueError: max() iterable argument is empty. opw-6283566 Forward-Port-Of: odoo/enterprise#121517 Forward-Port-Of: odoo/enterprise#120375
The AI icon now appears correctly on thinking notes in the chatter. This makes AI-generated activity easier for users to recognize and keeps the interface consistent after the recent migration.
Original PR description
This PR fixes an issue where the AI icon would not be shown on the thinking note of the chatter. The OWL3 migration added 'this.' prefixes to all template component references. This left 'isAiAgentChat' and 'props.channel' as bare context lookups (`ctx['isAiAgentChat']`, `ctx['props']`), both of which are undefined in the new rendering context. The fix adds 'this' in the xml to go through ctx['this'] to fetch each values correctly. task: 6346446
The Timesheet Assistant now gives cleaner, more relevant suggestions by excluding leave time and hiding to-do items that are not tied to a project. Users also get smoother entry with clearer default suggestion names and keyboard shortcuts for creating timesheets.
Original PR description
## Expected Behavior After Commit - Remove the green highlight when selecting a suggestion. - Add shortcuts for timesheet creation buttons. - Allow calendar events to be considered side activities - Exclude leave time from total hours, as leave time is already counted in the timesheet. - Do not show to‑do tasks (tasks without a project) in suggestions. - Restore previous suggestions for to‑do tasks when they later become linked to a project. - Add a default name for suggestions that do not have one. - Add hotkeys to Timesheet Assistant task-[6191451](https://www.odoo.com/odoo/project/4105/tasks/6191451) Forward-Port-Of: odoo/enterprise#121085 Forward-Port-Of: odoo/enterprise#120057
This update fixes an access issue affecting test employee types in payroll. It helps ensure payroll checks and warnings work correctly for authorized users, reducing friction during payroll validation.
Original PR description
task-6348716 Forward-Port-Of: odoo/enterprise#122264
Auto Plan now only assigns resources that match the role selected on a project planning slot. This prevents employees or resources from being scheduled for roles they are not assigned to, improving planning accuracy.
Original PR description
## Issue When using the *Auto Plan* feature on a planning slot with a Role and a Project set, a resource which operated on the same project will be chosen if available, without taking into account…
## Issue
When using the *Auto Plan* feature on a planning slot with a Role and a Project set, a resource which operated on the same project will be chosen if available, without taking into account the Role set on the slot.
## Steps to reproduce
1. Install Project Planning (`project_forecast`)
2. In Planning > Configuration > Roles, create two planning roles A and B
- Role A: Assign a resource R
- Role B: No resource
3. Open Planning (Schedule by Resource), and go back a few weeks (to prevent overlaps with potential demo data)
4. Create two new slots:
1. Set Role B and a random Project P, then click Auto Plan: there should be no available resource (because we didn't set any resource for Role B)
2. Set Role A and the same Project P, then click Auto Plan: it should assign the resource R assigned to Role A
5. After assigning a resource to the slot for Role A, edit the Open Shift for Role B again and click Auto Plan: **it assigns the same resource R, even though that resource is not assigned to Role B.**
## Cause
The `_get_open_shifts_resources` override in `project_forecast` looks for resources that were assigned to slots related to the same project. It does not filter resources based on the requested role.
https://github.com/odoo/enterprise/blob/885edbc270a86ab76e0a6eff4acb5767c0fe29d1/project_forecast/models/planning_slot.py#L104-L116
This means that resources that are not part of the requested role can be assigned to the slot, as long as the resource operated on another slot for the same project.
opw-6325744
Forward-Port-Of: odoo/enterprise#122742
Forward-Port-Of: odoo/enterprise#122035This update prevents an error when users enter a negative forecast demand in Manufacturing Planning. Negative remaining quantities are now applied to the first forecast as intended, keeping planning workflows from being interrupted.
Original PR description
Steps to reproduce: - Fresh DB - Add a negative number to the forecast demand in the last period Cause: A variable was used without declaration Fix: According to odoo/enterprise#56128, it was intended that any remaining negative quantity to add should be added to the first forecast. Forward-Port-Of: odoo/enterprise#122520 Forward-Port-Of: odoo/enterprise#122261
The Executive Summary report now counts both the start and end dates when calculating period length. This fixes Average Debtor Days values that were slightly understated for date ranges such as a full month.
Original PR description
`_report_custom_engine_executive_summary_ndays` returned `date_to - date_from`, which is the gap between the two dates, not the count of days they span. For example April 2026-04-01 to 2026-04-30 will returned 29 instead of 30, making Average Debtor Days incorrect. Add +1 so the day count is inclusive of both endpoints, matching the rest of the report's date handling. opw-6215362 Forward-Port-Of: odoo/enterprise#121151 Forward-Port-Of: odoo/enterprise#118953
USPS package type forms now show the unit of measure for dimensions, reducing confusion when entering package sizes. Shipping rate calculations now use the selected USPS service type, so businesses receive the correct rate when changing package or service options.
Original PR description
Issue ----- There are 2 issues with USPS rest: 1. USPS packagings do not have their size UOM displayed. This leads to confusion as users input in inches but the dimensions are treated as feet. 2.…
Issue ----- There are 2 issues with USPS rest: 1. USPS packagings do not have their size UOM displayed. This leads to confusion as users input in inches but the dimensions are treated as feet. 2. USPS returns the same rate regardless of the package type. Steps to reproduce ----- - Set USPS up - Open the Package Type form > go to its' Dimensions tab > Issue 1 - Set USPS up (domestic) - Select a `Domestic Rating Indicator` (eg LF - Flat Rate Box) - Create a SO with some product - Open the delivery widget and add a rate with USPS - Discard the changes - Go to the delivery method and change the rating (eg SP - Single Piece) - Go back to the SO - Open the delivery widget and add a rate with USPS > Issue 2, rate is the same as before Issue 1 ----- By default, there is no displayed UOM on the form because of https://github.com/odoo/odoo/blob/38c737c2a4cc29b48235a100cfa9d6152af73826/addons/stock_delivery/models/stock_package_type.py#L20-L33 We can change this behaviour for USPS specifically as done in Envia https://github.com/odoo/enterprise/blob/20cc61e69aa3f6a59de1e962b25ce11fa402bf22/delivery_envia/models/stock_package_type.py#L37-L46 Issue 2 ----- In `usps_rest_rate_shipment`, we request rates for every package of the delivery, which we receive as lists. We then iterate over the list to find the rate matching the `mail_class`. The problem is that this only filters over whether the delivery is domestic or international. We don't filter based on the actual service selected on the carrier (`usps_domestic_rating_indicator` for domestic and `usps_international_rating_indicator` for international). https://github.com/odoo/enterprise/blob/20cc61e69aa3f6a59de1e962b25ce11fa402bf22/delivery_usps_rest/models/delivery_usps.py#L224-L236 ----- Ticket: opw-6224918 Forward-Port-Of: odoo/enterprise#120789 Forward-Port-Of: odoo/enterprise#120594
This change fixes inconsistent automated test results for the VoIP tab by ensuring the required mail-related setup is always included. It helps keep validation runs stable and reduces the risk of false failures during release checks.
Original PR description
Depending on the runbot build test order/configuration "tab" tests introduced at [1] passed or not. This was because mail utils rely on mail models definition which are not explicitly defined in this test file. They are now defined through setupVoipTests to be consistent with other VoIP test files. [1]: https://github.com/odoo/enterprise/commit/37b89ba41dd7891a09592f24ecf30df5596f254c runbot-941401
This update fixes internal Sign app tests that could fail when demo data or previous manual activity existed in the database. It makes test checks more precise so development and quality assurance work can run more reliably without affecting customer-facing behavior.
Original PR description
Version: 19.0 `test_sign_request_notification`, `test_gc_removes_orphan_roles_and_dummy_items` ,`test_sign_tour` and `test_sign_tour_without_sign` fail locally when you run them on a db with demo…
Version: 19.0
`test_sign_request_notification`, `test_gc_removes_orphan_roles_and_dummy_items` ,`test_sign_tour` and `test_sign_tour_without_sign` fail locally when you run them on a db with demo data installed, after doing some manual testing/ operations on it.
- `test_sign_request_notification` builds `completion_mail_to_user` by searching `mail.mail` for any email addressed to the admin's address. If admin had received any other email before this test ran, it got counted too, so the assertion on `len(completion_mail_to_user)` became wrong. We now also filter by subject matching `sign_request.reference`, so it only counts the email this test's own sign request actually generated.
- `test_gc_removes_orphan_roles_and_dummy_items` relies on the helper `_get_signer_and_item_gc_context` to count dummy sign items (page < 0). That helper searched `sign.item` with no domain at all, so any dummy item left behind by a different template got added to `non_active_item_ids` and broke the `len(non_active_item_ids) == 4` check. We now scope that search to `template_id = sign_template.id`, so it only counts items belonging to the template created in the test.
- `sign_tour` had a step targeting `.o-autocomplete--dropdown-item:contains('Administrator')` in the signer autocomplete. After installing demo data the admin user is named `Mitchell Admin`, so the tour failed on databases using that name. Both contain 'Admin', so the trigger now matches on that instead.
taskid- 6329037
Forward-Port-Of: odoo/enterprise#121878Fixes an issue where some multi-day shift templates on round-the-clock schedules showed one extra minute of planned time. This keeps allocated hours aligned with the intended shift duration, improving the accuracy of planning reports.
Original PR description
**Problem:** On a round-the-clock (0h-24h) working schedule, shifts created from a shift template that spans more than one day get one extra minute added to their allocated time: an 8-hour shift…
**Problem:** On a round-the-clock (0h-24h) working schedule, shifts created from a shift template that spans more than one day get one extra minute added to their allocated time: an 8-hour shift shows 08:01. **Steps to reproduce:** 1. Create a working schedule with a 00:00 -> 24:00 attendance for every day (24h/day, "Full Day"). 2. Assign an employee to that schedule. 3. Create a multi-day-span shift template (e.g. 16:00 -> 00:00, 2 days). 4. Plan a shift for that employee using the template. 5. Observe the Allocated Time shows one minute more than expected (08:01). **Current behavior:** Allocated Time is one minute too long (e.g. 08:01 instead of 08:00), which throws off the customer's planning reports. **Expected behavior:** Allocated Time matches the template duration exactly (08:00). **Cause of the issue:** In `_calculate_start_end_dates`, the end of a multi-day-span shift is computed with `resource.calendar_id.plan_days(...)`. On a 0h-24h calendar each day ends at `time.max` (23:59:59.999999), so `plan_days` returns an end datetime carrying those stale seconds. The following `end.replace(hour=..., minute=...)` overwrites only the hour and minute, leaving `second=59, microsecond=999999`. The slot is therefore ~1 minute longer than intended, and `allocated_hours` rounds that up to 08:01. **Fix:** Resetting seconds and microseconds when rebuilding the end datetime keeps the slot aligned to the template's whole-minute boundary, regardless of how the underlying calendar represents the end of day. The hour/minute already come from the template, so the leftover sub-minute precision from `plan_days` is never meaningful and is what produces the drift. opw-6265238 Forward-Port-Of: odoo/enterprise#122157 Forward-Port-Of: odoo/enterprise#120219
Fixed an issue where reconciling multiple discounted invoices together from a bank statement could overstate the discount base in tax reports. This keeps tax return figures accurate when invoices share the same VAT tax and are paid in one batch.
Original PR description
Steps to reproduce 1. Create two customer invoices that share the same VAT tax, with a payment term granting an early payment discount. 2. Create one bank statement line whose amount equals the sum…
Steps to reproduce 1. Create two customer invoices that share the same VAT tax, with a payment term granting an early payment discount. 2. Create one bank statement line whose amount equals the sum of both invoices' discounted totals. 3. From the bank reconciliation widget, select both invoices and validate in a single batch reconciliation. 4. Open Accounting > Reporting > Tax Return, switch the variant to "Group by: Account > Tax". Issue The cash-discount expense row shows a Net base column equal to twice the real discount base. The Tax column is correct. The bank-statement reconciliation paths (set_line_bank_statement_line, set_batch_payment_bank_statement_line, _reconcile_payments) loop over each invoice and call _apply_early_payment_discount one invoice at a time. Each call writes one discount base line and one discount tax line on the resulting bank entry, so when two invoices share the same tax the bank entry ends up with two pairs carrying the same (account, partner, currency, tax_repartition_line_id, tax_ids). The SQL that feeds the tax report at https://github.com/odoo/odoo/blob/d7d0efd39a65bfb6fee307b661cd2523a6b8231d/addons/account/models/account_move_line_tax_details.py#L100 matches every base line of a tax with every tax line of that tax inside the same move. With two pairs sharing one tax that turns two rows into four, and SUM(base_amount) doubles. The Tax column does not double because the same SQL redistributes each tax line's recorded amount across its matched rows so the totals still add back to the original tax. The payment register flow does not have this problem because it calls _get_invoice_counterpart_amls_for_early_payment_discount once with every invoice, and that helper already collapses duplicates with the merge key at https://github.com/odoo/odoo/blob/f3b317310b84edb073009f7d15d7fec002f3ccf0/addons/account/models/account_move.py#L5082-L5093 opw-6199906 Forward-Port-Of: odoo/enterprise#122747 Forward-Port-Of: odoo/enterprise#117743
Restaurant preparation displays now update correctly when staff split combo meals back into individual items, without creating duplicate kitchen tickets or unnecessary alerts. The fix also improves course labels for floating orders and ensures displays only receive preparation lines for their configured product categories.
Original PR description
Issue: Breaking a combo back into individual lines was not notifying the preparation display. Fix: breakCombo now go through sendOrderInPreparation (with byPassPrint) the preparation display is updated and no ticket is printed. To avoid triggering a sound and a kitchen ticket for a reorganization the kitchen already knows about, thread a `silent` context flag through sendOrderInPreparation down to _send_load_orders_message.
Preparation displays are now notified when an order is changed, so kitchen or prep teams see the latest information without missing updates. This helps avoid confusion and keeps order preparation aligned with point-of-sale changes.
Original PR description
Before this commit, when an order change was updated, the pdis were not notified of the change. This commit adds a call to the `_send_load_orders_message` method of the pdis to notify them of the change.
The document selection dialog no longer shows document management actions when users select files to attach or link. This keeps the dialog focused on choosing documents and avoids showing irrelevant controls in that workflow.
Original PR description
When selecting documents for attachment/link, control panel actions were displayed upon selection. The document selection dialog uses the secondary documents view introduced in: https://github.com/odoo/enterprise/pull/89030/changes/f93c159c106d1dde70910ec590f8739e549b19cf Several document management actions were already hidden through the `documents_view_secondary` context, but `DocumentsAction` was still displayed upon selection. Hide `DocumentsAction` in the secondary view. Task-6236888 Forward-Port-Of: odoo/enterprise#122536 Forward-Port-Of: odoo/enterprise#119219
13 changes
Enhancements to existing features
Budget reports now use the same profitability criteria as analytic profitability reporting. This helps ensure budget figures include the right analytic entries and stay consistent with profitability views.
Original PR description
Use the new field analytic_profitability in the conditions of the query to get the account analytic lines of the budget report task-4959636 Forward-Port-Of: odoo/enterprise#121760
Resolved issues and error corrections
Project users can now shorten a task deadline in the Gantt view even when the task has no follow-up tasks. This prevents a server error and keeps schedule adjustments working smoothly for simple projects.
Original PR description
## Current behavior: In the Project's app, switch to Gantt chart's view, when changing the deadline of a single task by shrinking its right edge, the server throws `ValueError: max() iterable…
## Current behavior: In the Project's app, switch to Gantt chart's view, when changing the deadline of a single task by shrinking its right edge, the server throws `ValueError: max() iterable argument`` is empty when calling end_date = max(candidates.mapped(stop_date_field_name)). ## Steps to reproduce: 1. In version 19.0 and above, install Project app 2. Create a project and only 1 single task 3. Switch to Gantt chart view 4. Try changing the deadline of a task by dragging its right edge 5. Observe that extending the task's deadline by dragging to the right works fine, but shrinking the deadline by dragging to the left will cause server to throw RPC_ERROR: Odoo Server Error and ValueError: max() iterable argument is empty. ## Cause of the issue: - A task with NO successors will cause candidates gathered via dependency_inverted_field_name to be empty. - The empty candidates recordset then get called by max(candidates.mapped(stop_date_field_name)), which is the reason causing error message ValueError: max() iterable argument is empty. opw-6283566 Forward-Port-Of: odoo/enterprise#121517 Forward-Port-Of: odoo/enterprise#120375
Cancelled UrbanPiper delivery orders are now excluded from active delivery counts. This prevents affected POS sessions from failing to reopen after a delivery provider cancels an order.
Original PR description
### Steps to reproduce 1. Configure UrbanPiper and start a POS session. 2. Receive an order from the delivery provider. 3. Accept the order and mark it as **Ready**. 4. Cancel the order from the…
### Steps to reproduce 1. Configure UrbanPiper and start a POS session. 2. Receive an order from the delivery provider. 3. Accept the order and mark it as **Ready**. 4. Cancel the order from the delivery provider. 5. Reopen the running POS session. ### Current behavior When a delivery provider cancels an order, the `delivery_status` is updated to `cancelled`, while the POS order state remains (`draft`, `paid`, or `done`). As a result: * Cancelled deliveries are still included in the active delivery order count. * `_get_urbanpiper_order_count()` attempts to map the `cancelled` status, which is not present in `status_map`, raising a `KeyError`. * The POS UI fails to load, preventing users from reopening the running session. ### Expected behavior Cancelled delivery orders should not be considered active delivery orders and should not be included in the delivery status count, allowing the POS session to open normally. ### Solution Exclude orders with `delivery_status = 'cancelled'` from the active delivery order count computation. This prevents the `KeyError` and ensures cancelled delivery orders are ignored when computing active delivery statistics. [Video reproducing the issue](https://drive.google.com/file/d/1XdiylekWV-q6LTbvhCgbyd_KDKlG2imz/view?usp=sharing) --- **opw-6353861**
The AI assistant button in the Sign send workflow now opens correctly instead of showing an error. This prevents interruptions when users prepare signature requests with AI-assisted content.
Original PR description
Version: saas-19.3 Steps to Reproduce: 1. Open a sign template and click "Send" 2. Click the AI button in the wizard Issue: Clicking the AI button raises ValueError: "The record must inherit from 'mail.thread'". Cause: `sign.template` does not inherit `mail.thread`, but interfaceKey `mail_composer` requires it. Fix: Added `get interfaceKey()` to `MailComposerChatGPT` so subclasses can override it. `SignAIButton` in `sign_ai` overrides interfaceKey to `html_field_record`. Taskid: 6303226
Stripe expense authorizations now correctly recognize merchant category codes that fall within configured ranges, reducing incorrect errors when expenses are processed. Declined Stripe expenses also avoid duplicate refusal messages, making expense records clearer for users and approvers.
Original PR description
# [FIX] hr_expense_stripe: Fix MCC ranges Context: Since 3e52d875 when receiving an authorization whose MCC fits in a range we would not find it in the search. This is logical yet we return an error before checking properly mcc codes with range included After this commit: This will also check that the authorization MCC exist if we don't directly find the range. We move the "not found" error after that check too The forgotten tests have been added into the overrides opw-6185961 opw-6288399 # [FIX] hr_expense_stripe: Fix double refusal of expenses Context: When an expense is created through a declined stripe authorization, the expense is refused twice, resulting in a duplicated refusal message After this commit: Do not refuse already refused expenses Forward-Port-Of: odoo/enterprise#121474
Shipments using Envia insurance now send the insurance details in the format expected by Envia. This ensures insured deliveries can generate the correct insurance documents, reducing fulfillment issues for affected Mexican delivery flows.
Original PR description
Issue ----- Insurance set on the delivery method is not correctly being communicated to Envia. Steps to reproduce ----- - Create a MX company - Set up Envia - Fedex Nacional Economico (ground) - 10% insurance - Create a MX client - Create a product (with some weight) - Create a SO using the delivery method & confirm - Validate the picking > No insurance pdf is being printed Cause ----- We are passing the insurance value as a `insurance` field on the shipment, which is not what the API expects. We should instead pass it in `additionalServices` as shown in the example of https://docs.envia.com/docs/additional-services#how-to-add-services-to-a-shipment ----- Ticket: opw-5254952 Forward-Port-Of: odoo/enterprise#118966
This fix makes Sign app automated tests run reliably on databases that include demo data or prior manual activity. It prevents unrelated emails, templates, or administrator name variations from causing false test failures, improving release validation without changing customer-facing behavior.
Original PR description
Version: 19.0 `test_sign_request_notification`, `test_gc_removes_orphan_roles_and_dummy_items` ,`test_sign_tour` and `test_sign_tour_without_sign` fail locally when you run them on a db with demo…
Version: 19.0
`test_sign_request_notification`, `test_gc_removes_orphan_roles_and_dummy_items` ,`test_sign_tour` and `test_sign_tour_without_sign` fail locally when you run them on a db with demo data installed, after doing some manual testing/ operations on it.
- `test_sign_request_notification` builds `completion_mail_to_user` by searching `mail.mail` for any email addressed to the admin's address. If admin had received any other email before this test ran, it got counted too, so the assertion on `len(completion_mail_to_user)` became wrong. We now also filter by subject matching `sign_request.reference`, so it only counts the email this test's own sign request actually generated.
- `test_gc_removes_orphan_roles_and_dummy_items` relies on the helper `_get_signer_and_item_gc_context` to count dummy sign items (page < 0). That helper searched `sign.item` with no domain at all, so any dummy item left behind by a different template got added to `non_active_item_ids` and broke the `len(non_active_item_ids) == 4` check. We now scope that search to `template_id = sign_template.id`, so it only counts items belonging to the template created in the test.
- `sign_tour` had a step targeting `.o-autocomplete--dropdown-item:contains('Administrator')` in the signer autocomplete. After installing demo data the admin user is named `Mitchell Admin`, so the tour failed on databases using that name. Both contain 'Admin', so the trigger now matches on that instead.
taskid- 6329037
Forward-Port-Of: odoo/enterprise#121878This fix prevents an error when users enter a negative forecast demand in Manufacturing Planning. The system now applies any remaining negative adjustment to the first forecast as intended, keeping planning workflows stable.
Original PR description
Steps to reproduce: - Fresh DB - Add a negative number to the forecast demand in the last period Cause: A variable was used without declaration Fix: According to odoo/enterprise#56128, it was intended that any remaining negative quantity to add should be added to the first forecast. Forward-Port-Of: odoo/enterprise#122520 Forward-Port-Of: odoo/enterprise#122261
Fixed an issue that caused an error when users clicked to audit values in the Balance Sheet grouped by analytic account. This lets finance users reliably drill into report figures without interruption.
Original PR description
Currently an error occurs when user tries to audit a cell when Balance Sheet is grouped by an analytic acccount. Steps to replicate: - Install accountant with demo data and turn on Analytic…
Currently an error occurs when user tries to audit a cell when Balance Sheet is grouped by an analytic acccount.
Steps to replicate:
- Install accountant with demo data and turn on Analytic Accounting.
- Open Balance Sheet Report > Group By an Analytic Account > Click on Any Value under an Analytic Account Column.
Error:
```
File '/home/odoo/src/enterprise/saas-19.3/account_reports/models/account_report.py', line 2876, in dispatch_report_action
return report_method(model, *args)
File '/home/odoo/src/enterprise/saas-19.3/account_reports/models/balance_sheet.py', line 28, in action_audit_cell
action['context'].update({
AttributeError: 'str' object has no attribute 'update'
```
Cause:
- When clicking on a report cell, `dispatch_report_action()` calls `action_audit_cell()` of the corresponding report (Balance Sheet in this case) which in turn calls `action_audit_cell()` of `account.analytic.report`.
- When the flow reaches [1], the window action for analytic items is fetched, where its [context] is returned as a string instead of a dictionary.
- This action is then received [here] with `context` as a string, and attempting to update it results in an error.
Solution:
- Converted the string to dict using `literal_eval()`.
[1]: https://github.com/odoo/enterprise/blob/a26981667361839ad38f45da5a6f23ae8e6478f1/account_reports/models/account_analytic_report.py#L208
[context]: https://github.com/odoo/odoo/blob/824446b65cbe3850f88f56090f0473f0e94bf4f3/addons/account/views/account_analytic_line_views.xml#L88-L91
[here]: https://github.com/odoo/enterprise/blob/b5f884a49344aa097c20fc128e9d290b97970f1a/account_reports/models/balance_sheet.py#L28
opw-6311673
sentry-7513784149Fixed an issue where shifts based on multi-day templates in round-the-clock schedules could show one extra minute of allocated time. This keeps planned shift durations accurate and prevents small errors from affecting planning reports.
Original PR description
**Problem:** On a round-the-clock (0h-24h) working schedule, shifts created from a shift template that spans more than one day get one extra minute added to their allocated time: an 8-hour shift…
**Problem:** On a round-the-clock (0h-24h) working schedule, shifts created from a shift template that spans more than one day get one extra minute added to their allocated time: an 8-hour shift shows 08:01. **Steps to reproduce:** 1. Create a working schedule with a 00:00 -> 24:00 attendance for every day (24h/day, "Full Day"). 2. Assign an employee to that schedule. 3. Create a multi-day-span shift template (e.g. 16:00 -> 00:00, 2 days). 4. Plan a shift for that employee using the template. 5. Observe the Allocated Time shows one minute more than expected (08:01). **Current behavior:** Allocated Time is one minute too long (e.g. 08:01 instead of 08:00), which throws off the customer's planning reports. **Expected behavior:** Allocated Time matches the template duration exactly (08:00). **Cause of the issue:** In `_calculate_start_end_dates`, the end of a multi-day-span shift is computed with `resource.calendar_id.plan_days(...)`. On a 0h-24h calendar each day ends at `time.max` (23:59:59.999999), so `plan_days` returns an end datetime carrying those stale seconds. The following `end.replace(hour=..., minute=...)` overwrites only the hour and minute, leaving `second=59, microsecond=999999`. The slot is therefore ~1 minute longer than intended, and `allocated_hours` rounds that up to 08:01. **Fix:** Resetting seconds and microseconds when rebuilding the end datetime keeps the slot aligned to the template's whole-minute boundary, regardless of how the underlying calendar represents the end of day. The hour/minute already come from the template, so the leftover sub-minute precision from `plan_days` is never meaningful and is what produces the drift. opw-6265238 Forward-Port-Of: odoo/enterprise#122157 Forward-Port-Of: odoo/enterprise#120219
Batch bank reconciliation now combines duplicate early-payment discount entries when multiple invoices share the same tax. This prevents the tax return from overstating the discount base amount, helping accounting reports stay accurate.
Original PR description
Steps to reproduce 1. Create two customer invoices that share the same VAT tax, with a payment term granting an early payment discount. 2. Create one bank statement line whose amount equals the sum…
Steps to reproduce 1. Create two customer invoices that share the same VAT tax, with a payment term granting an early payment discount. 2. Create one bank statement line whose amount equals the sum of both invoices' discounted totals. 3. From the bank reconciliation widget, select both invoices and validate in a single batch reconciliation. 4. Open Accounting > Reporting > Tax Return, switch the variant to "Group by: Account > Tax". Issue The cash-discount expense row shows a Net base column equal to twice the real discount base. The Tax column is correct. The bank-statement reconciliation paths (set_line_bank_statement_line, set_batch_payment_bank_statement_line, _reconcile_payments) loop over each invoice and call _apply_early_payment_discount one invoice at a time. Each call writes one discount base line and one discount tax line on the resulting bank entry, so when two invoices share the same tax the bank entry ends up with two pairs carrying the same (account, partner, currency, tax_repartition_line_id, tax_ids). The SQL that feeds the tax report at https://github.com/odoo/odoo/blob/d7d0efd39a65bfb6fee307b661cd2523a6b8231d/addons/account/models/account_move_line_tax_details.py#L100 matches every base line of a tax with every tax line of that tax inside the same move. With two pairs sharing one tax that turns two rows into four, and SUM(base_amount) doubles. The Tax column does not double because the same SQL redistributes each tax line's recorded amount across its matched rows so the totals still add back to the original tax. The payment register flow does not have this problem because it calls _get_invoice_counterpart_amls_for_early_payment_discount once with every invoice, and that helper already collapses duplicates with the merge key at https://github.com/odoo/odoo/blob/f3b317310b84edb073009f7d15d7fec002f3ccf0/addons/account/models/account_move.py#L5082-L5093 opw-6199906 Forward-Port-Of: odoo/enterprise#122747 Forward-Port-Of: odoo/enterprise#117743
The document selection dialog no longer shows document management actions when users select files to attach or link. This keeps the dialog focused on choosing documents and avoids exposing actions that are not relevant in that context.
Original PR description
When selecting documents for attachment/link, control panel actions were displayed upon selection. The document selection dialog uses the secondary documents view introduced in: https://github.com/odoo/enterprise/pull/89030/changes/f93c159c106d1dde70910ec590f8739e549b19cf Several document management actions were already hidden through the `documents_view_secondary` context, but `DocumentsAction` was still displayed upon selection. Hide `DocumentsAction` in the secondary view. Task-6236888 Forward-Port-Of: odoo/enterprise#122536 Forward-Port-Of: odoo/enterprise#119219
Fixed an issue where printing the Journal Audit report as a PDF could add a completely blank final page when the global tax summary was not included. This makes exported reports cleaner and avoids confusion for accounting users sharing or archiving audit documents.
Original PR description
Steps to reproduce: 1. Set the active company as My Company (san francisco) 2. Navigate to Accounting > Review > Journal Audit 3. Remove all journals from the report except Bank and Misc. 4. Use the PDF action button to print the report. 5. The last page of the report is completely empty. https://drive.google.com/file/d/1otpniJgt1UNCe2hrUBwqIK58dGuXpu8T/view?usp=sharing This commit ensures that the Journal Audit report does not have blank pages when the global tax summary section is not present. It uses some features of QWeb outlined in the following docs article: https://www.odoo.com/documentation/19.0/developer/reference/frontend/qweb.html#loops opw-6224670 Forward-Port-Of: odoo/enterprise#121068
38 changes
New functionality added to Odoo
Adds Belgian payroll reporting for forms 274.20 and 281.20, covering remuneration and withholding tax declarations for company executives. This helps businesses meet Belgian payroll compliance requirements more directly within Odoo.
Enhancements to existing features
Belgian payroll reporting now includes pool cars in both vehicle lists and related employer contribution calculations. This helps companies keep fleet-related payroll declarations more complete and aligned with Belgian reporting requirements.
Original PR description
. Add pool cars in vehicles list . Add pool cars in vehicles contribution task-6147532
Australian payroll data has been reorganized to make setup and leave handling clearer, with updated demo employees and contracts for easier demonstrations. Payroll and reporting wording has also been adjusted to better match Australian business terminology, improving usability for local teams.
Original PR description
## [IMP] l10n_au_hr_payroll{_{account,api}}: Revamp tooltips, master and demo data This revamp ensures AU-specific payroll and leave handling is more organized and demo-ready. Update…
## [IMP] l10n_au_hr_payroll{_{account,api}}: Revamp tooltips, master and demo data
This revamp ensures AU-specific payroll and leave handling is more organized and demo-ready.
Update hr_work_entry_type_data:
- Group work entry types by global/AU categories.
- Set default working schedule for AU companies to 38-hour resource calendar.
- Add time off types and convert paid time off to annual leave (avoid delete/create; update in place).
Demo data enhancements:
- Add employee images.
- Include country_id (AU) in hr_employee_demo.
- Revamped demo employee and contract data (9 employees in total)
Additional fixes and improvements:
- Add tooltips for improved UX in payroll/leave interfaces.
task-[5112796](https://www.odoo.com/odoo/all-tasks/5112796)
odoo/odoo#233335
odoo/upgrade#10302
## [I18N] account_reports, hr_payroll: revamp AU translations
We update some translations to be more aligned with local lingo.
task-[5112796](https://www.odoo.com/odoo/all-tasks/5112796)
odoo/odoo#233335
odoo/upgrade#10302Saudi payroll now supports a 30-day pay schedule so salary calculations can follow local legal requirements more accurately. The update also improves unpaid leave, GOSI contribution, allowance, and deferred amount calculations, helping reduce payroll discrepancies across different month lengths.
Original PR description
Purpose: Calculations in SA localization are done based on 30-day month basis accourding to the law. So, in this task we add 30 day pay schedule to allow 3 options: - Wroking days => Set schedule pay…
Purpose:
Calculations in SA localization are done based on 30-day month basis accourding to the law.
So, in this task we add 30 day pay schedule to allow 3 options:
- Wroking days => Set schedule pay as monthly and calendar as a normal one
- Calendar days => Set schedule pay as monthly and calendar as a full week one
- 30 days => Set schedule pay as 30_monthly and calendar as a full week one
Current behavior:
- changed the hardcoded value of 30 in salary rules to use number of days in the month accourding to the schedule pay
- corrected the computation of gosi rules to include all unpaid days in calculation
- changed some rules to use the correct category of `SA_ALW` instead of all allowances
- added a rule for deferred amount for the cases where the the employee took a full unpaid month in a non 30-day month
- added tests for 30-day pay schedule
Note that changes in tests are mainly because we are using working days instead of hardcoded 30 days per month
task-id: 6102084The UrbanPiper POS test order wizard can now validate discounts applied to individual products, not just the full order. Test order data also includes product taxes, making trial orders better match real customer orders and reducing the chance of configuration issues going unnoticed.
Original PR description
### Before this commit: - Test order wizard only supported order-level discount. - No way to validate line discount behavior from the test order flow. - Product Taxes were not included in the test order payload. ### After this commit: - Added `line_discount` field in the test order wizard. - Updated test order payload to include item-level discounts. - Added taxes in the test order payload based on the product taxes. - Updated test case to use the new `line_discount` field instead of passing it through context. Task:5240346
The timesheet timer now opens with a likely project already selected based on the employee's recent timesheets, while still prioritizing the project or task currently being viewed. It also avoids preselecting archived or template records, reducing mistakes and making time logging faster.
Original PR description
When opening the timesheet systray, the timer is now prefilled with the project to which the employee's three most recent timesheets are all linked, since they are most likely to keep logging time on it. The currently viewed project or task takes precedence over the favorite project, and viewing a project form now prefills the timer as well, just like task views already do. task-6290859 Forward-Port-Of: odoo/enterprise#120028
The rental sales configurator has been aligned with a related platform update to improve how product configuration data is handled. This should help rental quotation workflows stay responsive and consistent with the wider sales system, with no expected change to day-to-day user behavior.
Original PR description
Update method signature according to community PR. - https://github.com/odoo/odoo/pull/247381 task-3891049
The VoIP phone country selector now falls back to the user's or company country when the last call has no country information. This makes dialing smoother by showing a relevant default country and also avoids access-related issues when country data cannot be read.
Original PR description
When last call has no country, country selector fallback to user's country to show. Task-6321854
Payment users can now start individual or batch payments directly from the payment list, with clearer grouping, clickable batches, and visible Payment Initiation Service status. This reduces navigation and helps users understand which payments will be included before launching a bulk payment.
Original PR description
This commit makes the payment initiation workflow more intuitive
and accessible with the following UX improvements:
- Group payments by batch by default (since the batch list view
is restricted to debug mode).
- Add inline "Pay" buttons directly to standalone payment rows
and batch group-by headers.
- Make batches clickable directly from the list view.
- Display the PIS (Payment Initiation Service) status directly
in the list view for better visibility.
- Allow users to initiate a bulk payment from any single payment
within a batch. This includes a confirmation screen showing
all related payments in the batch before execution.
PS: Adding conditional buttons in the groupby batch_payment_id will
raise a traceback for empty lists if sample data is enabled. Turning
it off here to avoid the traceback. Will be reverted after the JS
team makes a fix.
task-6123868Budget reporting now uses the same profitability setting as analytic profitability views when selecting analytic lines. This helps ensure budget figures are consistent with profitability analysis, reducing confusion when comparing reports.
Original PR description
Use the new field analytic_profitability in the conditions of the query to get the account analytic lines of the budget report task-4959636 Forward-Port-Of: odoo/enterprise#121760
Project task schedules now display unavailable time for terminated assignees in grey. This makes it easier for planners to spot assignments involving former employees and adjust staffing accordingly.
Original PR description
When a task assignee is a terminated, their unavailability is displayed in grey in the task gantt view. After this pr https://github.com/odoo/enterprise/pull/62045 merge will add test case Task-5076834
Online delivery order cancellations are now recorded in the point-of-sale order history with who cancelled them and why. This gives teams clearer visibility into cancellation patterns and makes support or operational investigations easier.
Original PR description
Before this commit: ------------------- - Online delivery order cancellations were not logged, making it difficult to determine the cancellation source and reason. After this commit: ------------------ - Added logs for online delivery order cancellations in the PoS order chatter. - The logs now capture both the cancellation source (Odoo POS or UrbanPiper) and the cancellation reason, improving traceability and debugging. Task-6244499
Planning reports now show time-based figures in hours and use clearer business-friendly labels such as Actual Time, Actual Revenue, and Time Variance. Report names and empty-state guidance were also improved, making it easier for users to understand planned versus actual work and project progress.
Original PR description
* _ = project_timesheet_forecast, project_timesheet_forecast_sale - Format all time-based measures in hours for better readability and consistency - Rename measures for clarity: | Initial Value | New…
* _ = project_timesheet_forecast, project_timesheet_forecast_sale - Format all time-based measures in hours for better readability and consistency - Rename measures for clarity: | Initial Value | New Value | |-----------------------------|-----------------------------------| | Effective Billable Time | Actual Billable Time | | Effective Margin | Actual Margin | | Effective Non-Billable Time | Actual Non-Billable Time | | Effective Revenues | Actual Revenue | | Effective Time | Actual Time | | Effective Costs | Actual Costs | | Planned Revenues | Planned Revenue | | Time Remaining | Time Variance (Planned − Actual) | | Time Difference | Time Variance (Planned − Actual) | - Rename reports: | Initial Value | New Value | |--------------------------------|-----------------------------------| | planning / timesheets analysis | Planning & Timesheets Analysis | | planning / attendance analysis | Planning & Attendance Analysis | - Improve empty state helper message: `No data yet! Track your projects’ progress by comparing planned hours with actual hours recorded` Task: 6042556
French fiscal declaration reports now let users choose a year with a date picker instead of typing it as plain text. This reduces entry mistakes and makes the reporting workflow clearer for users completing the declaration.
Original PR description
For the french fiscal declaration, a line of the report needed a year to be enter by the user. Instead of using a string, we think it would be better to use a datetime picker with the precision of the year. This commit will introduce that. task-6159852
Resolved issues and error corrections
Refunded point-of-sale orders that fully cancel out matching pay-later customer account payments are now hidden from the Settle Orders list. This reduces clutter and prevents staff from seeing orders that no longer require settlement, making customer account balances clearer.
Original PR description
Currently, if you refund an order made on the customer account with the customer account as well, you can still see the order in the list of orders to settle. Steps to reproduce: -------------------…
Currently, if you refund an order made on the customer account with the customer account as well, you can still see the order in the list of orders to settle. Steps to reproduce: ------------------- * Open shop * Make an order using the customer account for a customer, don't invoice it * Refund one of the order using the customer account, don't invoice it * Make a new order using the customer account * In the customer list, find the customer used and select "Settle Orders" > The 2 orders are present in the list Why the fix: ------------ Originally the list would only show the orders for chich the customers have due (>0). https://github.com/odoo/enterprise/commit/bf4b6043b999b4a081b1afa73fc4113bf4db28f8 But recently the code we also see the refunds in the list as well. https://github.com/odoo/enterprise/commit/12af23d5382e972facfaa999e4c5ab30c97e8d1f However this new behavior is not visible if, with the refund, the customer account temporarily falls to 0. So currently we have some refunds that impact the amount to settle and some that don't. Originally we were thinking that either we should show all refunds in that list (given they use the customer account) or we shouldn't show any as it was previously. Both solutions are not ideal. * Showing them all would get the list bigger than it is and would require the customer to select the order and its refund(s) and settle them together. Since refunds are not usually done right after the order they would not be close it that list. However this solution would enable the option to remove the orders from the list requiring a few step from the customer. * Showing none isn't idea either with this use case as it means that we still see orders that were cancelled out by their refunds. To remove to order the customer has two options. Either going backend and searching the order and its refund(s) and invoice them, either settling the order but that means that now there's money deposited on the customer account. Any of the two option isn't perfect a it still requires manual intervention from the customer and wouldn't work on previous data. Creating a server action to correct those data wouldn't have been feasible either. Instead, the approach we're taking is the following: When loading the list of order to settle we want to remove the orders and the potential refunds were the customer account is evened out. We only need to look at the orders of the partners that contains refunds for which the customer account was used. If the sum of the transactions made on the customer account is 0 we can say that the order and its refunds have cancelled out each other (in terms of customer account) and we don't show them if the list of orders remaining to settle. opw-6170830 Forward-Port-Of: odoo/enterprise#117725
This update adjusts how rental product availability is handled in the online store. It helps ensure customers see more accurate stock information when browsing or booking rental products, reducing confusion and potential order issues.
Original PR description
task-4826932 See also: - https://github.com/odoo/odoo/pull/265605
The Belgian payroll dashboard now opens reliably when checking the "Employees Under Minimum Wage" warning for companies with multiple CP200 employees. This prevents an error that could block payroll teams from reviewing wage compliance alerts.
Original PR description
Opening the Payroll dashboard may crashes with an error: - Have a Belgian company with 2 or more CP200 employees having active contracts - Create or modify a contract for at least 2 of them (this marks l10n_be_computed_seniority_years as dirty for the batch) - Open the Payroll dashboard, the "Employees Under Minimum Wage" warning evaluation crashes In _compute_l10n_be_computed_seniority, the for version in cp200_versions loop was incorrectly referencing self instead of version. Since self is the full batch recordset, self.employee_id returns a multi-record set, causing ensure_one() to fail inside _get_first_version_date. task-6358718
Belgian payroll now calculates bike reimbursements using the correct rates for CP200 and CP302 employees, instead of applying an incorrect daily cap. This helps ensure payslips reflect the legally expected reimbursement amounts and reduces payroll correction work.
Original PR description
Steps to reproduce: 1. Employee Setup: CP200 or CP302, Bike 18 km. 2. Action: Compute 05/2026 payslip (21 worked days) and close pay. For CP200 - Got 226.80€ (stuck at 10.80€/day cap) -> Expected 204.12€ (18 km × 2 × 21 days × 0.27€). Solution: - Add missing rule parameters and update existing. - Update Python logic to use rates based on Joint Committee code with safe national fallback. Task: 6334739
Users can now preview canceled subscription orders without encountering an error. Canceled subscriptions are shown using the standard order preview instead of the subscription-specific view, preventing a crash and keeping the preview experience reliable.
Original PR description
Currently, an error occurs when a user previews a canceled subscription order. **Steps to Reproduce:** - Install `sale_subscription` module. - Go to `Subscriptions` and create a `subscription order`…
Currently, an error occurs when a user previews a canceled subscription order.
**Steps to Reproduce:**
- Install `sale_subscription` module.
- Go to `Subscriptions` and create a `subscription order` with:
- a `subscription product`,
- a `recurring plan`,
- an `Until` (end date) value.
- `Cancel` the subscription order.
- Click `Preview`.
`TypeError: unsupported operand type(s) for +: 'bool' and 'relativedelta'`
When previewing a subscription order, the portal view is rendered. During rendering, the
subscription portal template is used, which computes tax values and requires calculating the
next invoice date based on the recurring plan's billing period. However, for canceled
subscription orders, next_invoice_date is False because it is only set when the order is in
the sale state. As a result, an error is raised [2].
This commit ensures that only subscription orders in the sale state use the subscription
portal template. Canceled subscription orders use the default sale order preview, similar
to orders in the draft and sent states. This is appropriate because canceled subscriptions
are not correctly displayed in the subscription portal, and they should not attempt to
render the subscription-specific portal view.
[1]- https://github.com/odoo/enterprise/blob/f833154b61fdb73c24d99462815a55313212b909/sale_subscription/controllers/portal.py#L686-L687
[2]- https://github.com/odoo/enterprise/blob/f833154b61fdb73c24d99462815a55313212b909/sale_subscription/models/sale_order.py#L2172-L2175
sentry-7579114635
Forward-Port-Of: odoo/enterprise#122287This fixes an issue that prevented some Point of Sale users from opening the Preparation Display app due to an access rights check. The app now opens directly through the correct link, allowing authorized users with read access to use it as expected.
Original PR description
A recent fix in the base module requires users to have "write" access on ao model to execute its server actions. commit: odoo/odoo@846eb51a02baaf2e4f6e6780f8d0ceb23322c38b Previously, the Preparation Display was opened through the server action `action_pos_preparation_display_kitchen_display`, which then redirected to the URL action `action_pos_preparation_display_bar_restaurant_filter_link`. However, PS users only have read access on `pos.prep.display`. As a result, executing the server action triggers an access error when opening the Preparation Display. This commit bypasses the intermediate server action and opens the URL action directly. Task-6311320 Forward-Port-Of: odoo/enterprise#121293
Users responsible for rental pickups can now create and process rental orders even when they do not have broader inventory permissions. This removes an access error that blocked rental workflows while keeping the permission change limited to the rental transfer role.
Original PR description
Issue: --- It's not possible to create rental orders without stock.lot access. Steps to reproduce: 1- Change demo user access: - All inventory accesses: No 2- Enable `Rental Transfers`. 3- Login Demo user. 4- Create a rental order. You will get access error. Cause and Fix: --- `stock.lot` model is in only accessed by `group_stock_user`. As a result fields such as `reserved_lot_ids` will be problematic when we don't have stock access. We initially tried to fix the issue by limiting the problematic fields to group stock user. However that limits the user from rental pickup. Instead we are giving the required access to group rental picking user. opw-6281154 Forward-Port-Of: odoo/enterprise#122507 Forward-Port-Of: odoo/enterprise#120670
Contract versions now correctly receive additional values from contract templates, including hourly wage, analytic distribution, Monster integration, and attendance-based settings. This reduces manual corrections and helps ensure employee contract data stays consistent when templates are used.
Original PR description
[IMP] hr: adjustment in contract template loading Some fields were not loading from contract template to the versions properly. In standard modules (not localization ones), I have detected the fields that are in contract template form view but that is not loaded to versions. I have found that hourly_wage, analytic_distribution, monster_id, attendance_based are the missing ones. There are other some missing ones but they are computed so they are already computed from other things so they shouldn't be loaded directly. task - 6344952
Overtime durations are now stored with higher precision, reducing rounding errors that could slightly affect payroll amounts. This helps ensure employees are paid more accurately for overtime worked.
Original PR description
Overtime duration computed as fractional hours was rounded to 3 decimal places before being stored on the overtime line. Since 1 decimal hour = 3600 seconds, this gives only 3.6 seconds of precision and the rounding can go in the wrong direction due to floating-point representation. The fix consists in replacing the duration rounding to 4 decimals when building overtime work entries so stored durations keep sub-second precision needed for money computation. task-6212231 Forward-Port-Of: odoo/enterprise#122227 Forward-Port-Of: odoo/enterprise#119721
The My Timesheets view now uses the employee's own working schedule when showing unavailable days. This prevents users from accidentally logging time on days that were removed from their personal schedule.
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#122936 Forward-Port-Of: odoo/enterprise#113984
This update ensures UAE payroll rule parameters and salary rules are included when payroll data is refreshed. It helps keep payroll calculations aligned with the latest rule definitions and reduces the risk of incorrect payslip results.
Original PR description
. Add hr_rule_parameter_data & hr_salary_rule_data to _get_data_files_to_update() task-6347544 Forward-Port-Of: odoo/enterprise#122304
Fixed an issue where scanning a package during a warehouse picking could be incorrectly blocked when extra products were not allowed. The barcode app now correctly treats the scanned package as the destination package when appropriate, avoiding unnecessary errors and keeping warehouse workflows moving.
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 Forward-Port-Of: odoo/enterprise#122782 Forward-Port-Of: odoo/enterprise#121789
Completing a VoIP call activity now keeps the related message reference so follow-up updates can be applied properly. This prevents missing or incomplete activity history when calls are marked as done.
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 Forward-Port-Of: odoo/enterprise#122843 Forward-Port-Of: odoo/enterprise#118396
The executive summary now counts both the start and end dates when calculating report periods. This fixes Average Debtor Days so month-long periods, such as April 1 to April 30, use the correct 30-day span instead of 29.
Original PR description
`_report_custom_engine_executive_summary_ndays` returned `date_to - date_from`, which is the gap between the two dates, not the count of days they span. For example April 2026-04-01 to 2026-04-30 will returned 29 instead of 30, making Average Debtor Days incorrect. Add +1 so the day count is inclusive of both endpoints, matching the rest of the report's date handling. opw-6215362 Forward-Port-Of: odoo/enterprise#121151 Forward-Port-Of: odoo/enterprise#118953
Belgian payroll now accounts for loss of commissions when an employee has sick time off without a medical certificate, where this applies. This helps ensure payroll calculations reflect the correct compensation rules and reduces manual corrections.
Original PR description
Sick time off without certificate should grant loss on commissions if relevant Forward-Port-Of: odoo/enterprise#122807
When a signing request is completed, the person who sent it now receives the expected notification in their Odoo inbox if they use the "Handle in Odoo" preference. This helps users track completed documents without relying on email notifications.
Original PR description
## Issue When a user sets their notification to "Handle in Odoo" (`inbox`) and a sign requested is completed, they do not receive the expected notification. ## Steps to reproduce 1. Install *Sign*…
## Issue When a user sets their notification to "Handle in Odoo" (`inbox`) and a sign requested is completed, they do not receive the expected notification. ## Steps to reproduce 1. Install *Sign* (`sign`) 2. Sets the current user's notification preference to "Handle in Odoo" (`inbox`) 3. Create a sign request and send it to Marc Demo 4. As Marc Demo, sign the request 5. **The user who sent the sign request did not receive a notification to notify them that the request was signed.** ## Fix This is a partial backport of both https://github.com/odoo/enterprise/commit/463d6a2aae536356e6dee6b902f2e881dbc4fbda (saas-18.2) and a related fix https://github.com/odoo/enterprise/commit/41395dba4fd31222f5fd9fc94a84c977cf9334f9 (19.0). Before the first commit, users would not receive inbox notification when sign requests would be completed. ## Note to reviewer The issue only occurs in 18.0, as it is fixed by https://github.com/odoo/enterprise/commit/463d6a2aae536356e6dee6b902f2e881dbc4fbda in 18.2, but we can backport the fix from https://github.com/odoo/enterprise/commit/41395dba4fd31222f5fd9fc94a84c977cf9334f9 from 18.2 to 18.4 if desired. opw-6251702 Forward-Port-Of: odoo/enterprise#122740 Forward-Port-Of: odoo/enterprise#120740
The Timesheets app now shows the correct icon when the Timesheet Grid feature is installed. This fixes a visual inconsistency so users can more easily recognize the app in the menu.
Original PR description
Steps to reproduce: - Install timesheet_grid module Issue: - The Timesheets app uses the hr_timesheet icon because the Timesheets root menu web_icon is defined in hr_timesheet. Fix: - Override the web_icon field on hr_timesheet.timesheet_menu_root from timesheet_grid. Solution: - When timesheet_grid is installed, the Timesheets app now uses the timesheet_grid icon instead of the hr_timesheet one. task-5022883
Fixes an error that could occur when shortening the deadline of a standalone task in the Project Gantt view. Users can now adjust a single task's deadline without triggering a server error, making project scheduling more reliable.
Original PR description
## Current behavior: In the Project's app, switch to Gantt chart's view, when changing the deadline of a single task by shrinking its right edge, the server throws `ValueError: max() iterable…
## Current behavior: In the Project's app, switch to Gantt chart's view, when changing the deadline of a single task by shrinking its right edge, the server throws `ValueError: max() iterable argument`` is empty when calling end_date = max(candidates.mapped(stop_date_field_name)). ## Steps to reproduce: 1. In version 19.0 and above, install Project app 2. Create a project and only 1 single task 3. Switch to Gantt chart view 4. Try changing the deadline of a task by dragging its right edge 5. Observe that extending the task's deadline by dragging to the right works fine, but shrinking the deadline by dragging to the left will cause server to throw RPC_ERROR: Odoo Server Error and ValueError: max() iterable argument is empty. ## Cause of the issue: - A task with NO successors will cause candidates gathered via dependency_inverted_field_name to be empty. - The empty candidates recordset then get called by max(candidates.mapped(stop_date_field_name)), which is the reason causing error message ValueError: max() iterable argument is empty. opw-6283566 Forward-Port-Of: odoo/enterprise#121517 Forward-Port-Of: odoo/enterprise#120375
The Belgian salary package calculation now follows the legal mobility budget rules more accurately. It excludes holiday allowance and warrant-paid 13th month amounts where required, while including relevant commissions from the last 12 months, helping employers avoid incorrect budget caps.
Original PR description
https://lebudgetmobilite.be/fr/6-quel-est-le-montant-du-budget-mobilite#remunerationtotalebrute Simple and double holiday allowance should not be not accounted in the total brut remuneration for the cap of 20% for the mobility budget. 13th month should not be included if it is paid in warrants. This commit fixes the max mobility budhet amount computation by multipling the wage by 12.08 instead of 13, as we remove the simple holiday allowance. Ratio = 12 months + 13th month (except if paid in warrant) - Simple holiday allowance (0.92 month) Also, Commissions should included: Sum the commissions on payslips of the last 12 months for this employee. MB_Budget = monthly_wage * ratio / 5 + commissions Task-5948733
This fixes an error that could occur when a user entered a negative forecast demand in the Master Production Schedule. The system now handles remaining negative quantities as intended, improving reliability when adjusting production forecasts.
Original PR description
Steps to reproduce: - Fresh DB - Add a negative number to the forecast demand in the last period Cause: A variable was used without declaration Fix: According to odoo/enterprise#56128, it was intended that any remaining negative quantity to add should be added to the first forecast. Forward-Port-Of: odoo/enterprise#122520 Forward-Port-Of: odoo/enterprise#122261
This fix makes Sign app tests more reliable when run on databases that include demo data or previous manual activity. It prevents unrelated emails, leftover signing items, or different administrator display names from causing false test failures.
Original PR description
Version: 19.0 `test_sign_request_notification`, `test_gc_removes_orphan_roles_and_dummy_items` ,`test_sign_tour` and `test_sign_tour_without_sign` fail locally when you run them on a db with demo…
Version: 19.0
`test_sign_request_notification`, `test_gc_removes_orphan_roles_and_dummy_items` ,`test_sign_tour` and `test_sign_tour_without_sign` fail locally when you run them on a db with demo data installed, after doing some manual testing/ operations on it.
- `test_sign_request_notification` builds `completion_mail_to_user` by searching `mail.mail` for any email addressed to the admin's address. If admin had received any other email before this test ran, it got counted too, so the assertion on `len(completion_mail_to_user)` became wrong. We now also filter by subject matching `sign_request.reference`, so it only counts the email this test's own sign request actually generated.
- `test_gc_removes_orphan_roles_and_dummy_items` relies on the helper `_get_signer_and_item_gc_context` to count dummy sign items (page < 0). That helper searched `sign.item` with no domain at all, so any dummy item left behind by a different template got added to `non_active_item_ids` and broke the `len(non_active_item_ids) == 4` check. We now scope that search to `template_id = sign_template.id`, so it only counts items belonging to the template created in the test.
- `sign_tour` had a step targeting `.o-autocomplete--dropdown-item:contains('Administrator')` in the signer autocomplete. After installing demo data the admin user is named `Mitchell Admin`, so the tour failed on databases using that name. Both contain 'Admin', so the trigger now matches on that instead.
taskid- 6329037
Forward-Port-Of: odoo/enterprise#121878This fix makes USPS package dimensions display their unit of measure so users know whether they are entering inches or feet. It also ensures USPS shipping quotes reflect the selected package/service type instead of returning the same rate across different options.
Original PR description
Issue ----- There are 2 issues with USPS rest: 1. USPS packagings do not have their size UOM displayed. This leads to confusion as users input in inches but the dimensions are treated as feet. 2.…
Issue ----- There are 2 issues with USPS rest: 1. USPS packagings do not have their size UOM displayed. This leads to confusion as users input in inches but the dimensions are treated as feet. 2. USPS returns the same rate regardless of the package type. Steps to reproduce ----- - Set USPS up - Open the Package Type form > go to its' Dimensions tab > Issue 1 - Set USPS up (domestic) - Select a `Domestic Rating Indicator` (eg LF - Flat Rate Box) - Create a SO with some product - Open the delivery widget and add a rate with USPS - Discard the changes - Go to the delivery method and change the rating (eg SP - Single Piece) - Go back to the SO - Open the delivery widget and add a rate with USPS > Issue 2, rate is the same as before Issue 1 ----- By default, there is no displayed UOM on the form because of https://github.com/odoo/odoo/blob/38c737c2a4cc29b48235a100cfa9d6152af73826/addons/stock_delivery/models/stock_package_type.py#L20-L33 We can change this behaviour for USPS specifically as done in Envia https://github.com/odoo/enterprise/blob/20cc61e69aa3f6a59de1e962b25ce11fa402bf22/delivery_envia/models/stock_package_type.py#L37-L46 Issue 2 ----- In `usps_rest_rate_shipment`, we request rates for every package of the delivery, which we receive as lists. We then iterate over the list to find the rate matching the `mail_class`. The problem is that this only filters over whether the delivery is domestic or international. We don't filter based on the actual service selected on the carrier (`usps_domestic_rating_indicator` for domestic and `usps_international_rating_indicator` for international). https://github.com/odoo/enterprise/blob/20cc61e69aa3f6a59de1e962b25ce11fa402bf22/delivery_usps_rest/models/delivery_usps.py#L224-L236 ----- Ticket: opw-6224918 Forward-Port-Of: odoo/enterprise#120789 Forward-Port-Of: odoo/enterprise#120594
Code cleanup and technical improvements
Several parts of Odoo Enterprise were adjusted to rely on the newer offline capability rather than the older service. This keeps offline behavior consistent across accounting reports, return checks, and the home menu while reducing internal maintenance complexity.
Original PR description
instead of the service.
Several Odoo apps now use a more clearly named default access group instead of the previous public group reference. This is an internal cleanup that keeps access rules consistent without changing day-to-day business workflows.
Original PR description
https://github.com/odoo/odoo/pull/273361
20 changes
Enhancements to existing features
UK VAT returns now guide users to file through the relevant tax unit when their company belongs to one. This helps ensure HMRC connections and submissions use the tax unit’s VAT number instead of the individual company’s VAT number.
Original PR description
BEFORE: - Before this commit, when the current company is a member of the tax unit, there is no blocking level error for the user to select the tax unit. - And the vat used while creating a connection to the HMRC or while sending a tax report to the HMRC is of the current company. AFTER: - After this commit, there is one blocking level error, which tells the user that the current company is part of a tax unit, and on confirmation, the tax unit will automatically be selected for the current report. - And if the return contains the data of a tax unit, then the vat set on the tax unit will be considered while establishing the connection and sending the tax report to HMRC. Task-5865605 Forward-Port-Of: odoo/enterprise#122908 Forward-Port-Of: odoo/enterprise#107253
GSTR-1 JSON generation for Indian tax reporting has been optimized to use less memory and complete faster. This should improve performance when preparing GST filings, especially for larger datasets, without changing the report's business purpose.
Original PR description
This PR intends to improve both memory and time performance by using precomputing required values for GSTR-1 JSON generation. task-3941950 Community PR - https://github.com/odoo/odoo/pull/273087
Hong Kong payroll now participates in the automatic payroll data update process. This helps keep standard salary rules up to date for users, reducing manual maintenance while preserving rules that have been edited.
Original PR description
Currently, the "Payroll: Update data" cron doesn't work for HK payroll as we never set up the _get_data_files_to_update. We can set up the list of data files to keep up to date to better support our users by automatically keeping non-edited salary rules up to date. task-6360339
Budget reports now use the same analytic profitability criteria as profitability reporting. This helps ensure budget figures are based on the right analytic entries, improving consistency for financial review and decision-making.
Original PR description
Use the new field analytic_profitability in the conditions of the query to get the account analytic lines of the budget report task-4959636 Forward-Port-Of: odoo/enterprise#121760
The Sendcloud delivery option formerly called "Use Batch Shipping" is now labeled "Use Multicollo". This makes the wording clearer for customers and aligns Odoo with Sendcloud's own terminology.
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 Forward-Port-Of: odoo/enterprise#122133
Resolved issues and error corrections
The Sales Commission Achievements report now opens correctly when users apply the Current Period filter. This prevents an error that blocked access to current-period commission achievement data, improving reliability for sales teams and managers.
Original PR description
Steps to reproduce ------------------ 1. Install `sale_commission` (Enterprise). 2. Navigate to Sales -> Commission -> Achievements. 3. Click on the "Current Period" search filter. Issue ----- A `ValueError` is raised: `time data 'today' does not match format '%Y-%m-%d'`. The "Current Period" filter sends a domain using the string literal `'today'`. Natively, the ORM handles these special variables on evaluation. However, the `_search` override in `sale.commission.achievement.report` manually intercepted the raw domain leaves and tried to parse them directly via `datetime.strptime(d[2], '%Y-%m-%d')`, which crashes when encountering `'today'`. Solution -------- Pass the domain through the modern `Domain` API and use `optimize_full(model)` before extracting dates. This allows the ORM to properly resolve special tokens like `'today'` into actual `datetime.date` objects, which we can then safely filter via `isinstance()` without crashing.
The Point of Sale interface now shows change amounts with the correct negative sign, making payment information clearer for cashiers and customers. Related automated checks were updated to match the corrected display behavior.
Original PR description
In this commit: --------------- - The tours are updated to adapt the change as now frontend display the change amount with the correct (negative) sign. Community PR: https://github.com/odoo/odoo/pull/256776 task: 6074620 Forward-Port-Of: odoo/enterprise#116728 Forward-Port-Of: odoo/enterprise#112560
The outstanding payments list on invoices now consistently shows payments from newest to oldest. This makes it easier for users to understand recent payment activity and reduces confusion when reviewing invoices.
Original PR description
Before this commit: The invoice outstanding payments widget was not sorted by date globally, which could lead to confusion for users when viewing the widget. After this commit: This commit adds a sorting mechanism to ensure that the payments are displayed in descending order based on their date and ID. opw-6254080 Forward-Port-Of: odoo/enterprise#121642
When a credit note is created from a sales order in Mexican electronic invoicing, its lines now use the company's configured return account instead of the standard sales account. This helps ensure accounting entries are posted correctly when quantities are reduced after invoicing.
Original PR description
**PROBLEM** When creating a Credit Note from a Sale Order, the credit note lines uses the default account instead of using the return account set on the company. **STEP TO REPRODUCE** 1. Create a SO with a product. 2. Create an invoice and confirm it. 3. Return to the SO, and reduce the product qty (product invoice policy should be ordered qty for these steps). 4. Click again on create Invoice to create a Credit Note for the SO. 5. Notice the account on the product line is not the return account. **CAUSE** In `_create_invoices()` on the SO model, we first create the moves as invoice, and then switch them to credit note if the total is negative. This means the lines are created with the invoice default account. opw-6266882
This fix re-enables business checks that were temporarily paused during earlier inventory valuation changes. It ensures rental and Kenya electronic stock reporting tests reflect the updated way received goods are valued from vendor bills, reducing the risk of accounting or reporting discrepancies.
Original PR description
*: sale_stock_renting, l10n_ke_edi_oscu_stock Re-enable and adapt the tests skipped to fast merge the valuation refactoring made in 08b62a4bbcc6f9a391b2cc00a621ef4c76100229. The stock IO now values the receipt from the vendor bill, so the shared purchase fixtures `l10n_ke_edi_oscu` need to match the values provided in `l10n_ke_edi_oscu_stock` see for instance: https://github.com/odoo/enterprise/blob/ce68644f97ac28568b9497a18079a4ad5ce4a125/l10n_ke_edi_oscu/tests/expected_requests/save_purchase_2.json#L11-L13
Sales commission plans now prevent assigning a salesperson start date that falls after the plan’s end date. This avoids invalid commission setups and helps ensure salesperson eligibility dates match the approved plan period.
Original PR description
Version: 18.0 Steps to reproduce: - open sale commission plans and create a new plan with an effective period - go to the salesperson tab and add a salesperson - set the salesperson from date after the plan end date issue: salesperson period start date was accepted even if it was set after the plan end date fix: added validation to raise an error when the salesperson start date falls outside the plan effective period task id: 6241188 Forward-Port-Of: odoo/enterprise#118289
Hong Kong payroll now handles payslips with missing start or end dates without crashing. This prevents interruptions when users edit payslip periods and ensures end-of-year pay calculations are skipped safely when required dates are absent.
Original PR description
Currently, an error occurs when a user removes the payslip date. **Steps to Reproduce:** - Install `l10n_hk_hr_payroll` with demo data. - Switch to the `Hong Kong` company. - Go to `Payroll` >…
Currently, an error occurs when a user removes the payslip date. **Steps to Reproduce:** - Install `l10n_hk_hr_payroll` with demo data. - Switch to the `Hong Kong` company. - Go to `Payroll` > `Payslips` > `Payslips`. - Create a `payslip` and remove the `start` or `end` period. **Error 1:** `TypeError: unsupported operand type(s) for +: 'bool' and 'relativedelta'` **Error2:** `AttributeError: 'bool' object has no attribute 'month'` When a user removes the start or end date of a payslip, the system computes the Average Daily Wage. Based on the payslip dates, it finds the previous year's payslips [1]. If the start or end date is not set, it raises an error [2]. For the second error, when computing whether to include EOY pay, it compares the company's EOY pay date with the end date's month. If the end date is not set, accessing its month raises an error [3]. This commit ensures that when retrieving previous-year payslips, if the start or end date is not set, it returns an empty payslip recordset. It also ensures that when computing whether to include EOY pay, if the end date is not set, `include_eoy_pay` is set to `False`. [1]: https://github.com/odoo/enterprise/blob/ec8a009794863090351d91650aff727e6fbeab7e/l10n_hk_hr_payroll/models/hr_payslip.py#L124 [2]- https://github.com/odoo/enterprise/blob/ec8a009794863090351d91650aff727e6fbeab7e/l10n_hk_hr_payroll/models/hr_payslip.py#L209-L215 [3]- https://github.com/odoo/enterprise/blob/ec8a009794863090351d91650aff727e6fbeab7e/l10n_hk_hr_payroll/models/hr_payslip.py#L141
The self-ordering payment flow now verifies that the selected point-of-sale setup is a kiosk and has an IoT payment method before processing payment. This helps prevent incorrect or incomplete configurations from causing payment issues for customers.
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#122628 Forward-Port-Of: odoo/enterprise#121894
Sales orders linked to field service tasks now distinguish between free items that were already on the quotation and free materials added during the job. This prevents valid zero-price quotation lines from being skipped for invoicing and lets orders correctly show as fully invoiced once eligible lines are billed.
Original PR description
## [FIX] industry_fsm_sale: fix invoice status for zero price lines ### Issue: Without Anglo-Saxon accounting, the system incorrectly sets the invoice status of all zero price sales order lines…
## [FIX] industry_fsm_sale: fix invoice status for zero price lines
### Issue:
Without Anglo-Saxon accounting, the system incorrectly sets the invoice status of all zero price sales order lines linked to an FSM task to 'no'
This includes pre-existing lines that were already present on the quotation before confirmation. If a zero price line is pre-existing, it should follow the standard flow and be marked as 'to invoice'
Only lines added as materials from the field service task at a zero price should be considered included in the price and marked as 'no'
### Cause:
In `SaleOrderLine._compute_invoice_status`, the system forced `invoice_status = 'no'` for all zero price lines when Anglo-Saxon accounting was disabled
It failed to check if the lines were actually materials added via the FSM task or original quotation lines
### Fix:
A new `material_sale_lines` compute field is added to `project.task` to distinctly isolate and track lines added specifically as materials during the task execution
In `SaleOrderLine._compute_invoice_status`, the logic is updated to ensure that only zero price lines identified as FSM materials are set to 'no' when Anglo-Saxon accounting is disabled
Other pre-existing zero price lines properly remain as 'to invoice'
### Steps to reproduce:
- Install `industry_fsm_sale`
- In Settings > Users & Companies > Companies > Any company, add the field Anglo-Saxon using Studio (In 19.0+)
- Disable Anglo-Saxon on the current company
- Create a product Service (Fixed Price, that create a task in a Field Service Project)
- Create and confirm a Sale Order with the Service and one product with unit price 0
Before the fix, the pre-existing SO line with price 0 is
incorrectly considered as not to invoice ('no')
opw-6169802
------------------------------
## [FIX] industry_fsm_sale: sync sale order invoice status
### Issue:
When a sale order contains FSM material lines with a price of zero and Anglo-Saxon accounting is disabled, the overall sale order invoice status remains stuck on 'to invoice' even after all other invoiceable lines are fully invoiced
### Cause:
The standard `SaleOrder._compute_invoice_status` does not handle FSM business rules regarding zero price material lines that are marked as `invoice_status = 'no'`
Because these lines are never technically invoiced, the global order status fails to transition to 'invoiced'
### Fix:
Override `SaleOrder._compute_invoice_status` to recompute the status of confirmed orders linked to FSM tasks
We use the task's `material_sale_lines` to filter out material components
If all lines on the order are either 'invoiced' or are zero price FSM material lines with Anglo-Saxon disabled, the global sale order status is forced to 'invoiced'
### Steps to reproduce:
- Install `industry_fsm_sale`
- In Settings > Users & Companies > Companies > Any company, add the field Anglo-Saxon using Studio (In 19.0+)
- Disable Anglo-Saxon on the current company
- Create a product Service (Fixed Price, that create a task in a Field Service Project)
- Create and confirm a Sale Order with the Service and one product with unit price 0
- Add a Product from the Task (Use a price 0 product, or set the unit price to 0 on the SO)
- Create the invoice for the Sale Order
Before the fix, the Service and Pre-existing product are invoiced, but in the Other Info Tab of the SO, the status stays on 'To Invoice' instead of 'Fully Invoiced'
opw-6169802Users can now turn AI provider options on or off without deleting the saved API key. This makes AI configuration easier to manage while still requiring a key before a provider can be enabled.
Original PR description
Prior to this fix, user had to delete the API key set in order to disable the corresponding provider option in the ai config view. With this PR, we add an inverse method to allow the enable/disable provider option independently from the API key value being set. However, the API key value field must be non-empty to enable the provider option. task: 6331248
This fixes a gap where recurring products could be added to confirmed sales orders through the catalog without requiring a subscription plan. Business users now get the same warning regardless of how the product is added, preventing inconsistent subscription orders.
Original PR description
Steps to reproduce: --------------------------------------- 1. Install Subscription Module 2. Create and Confirm SO with no recurring plan and a non-recurring product 3. Add a recurring product >…
Steps to reproduce: --------------------------------------- 1. Install Subscription Module 2. Create and Confirm SO with no recurring plan and a non-recurring product 3. Add a recurring product > Save SO > Observe the User Error 4. Now add the same recurring product through Catalog View Observation: --------------------------------------- No User Error raised stating 'You cannot save a sale order with recurring product and no subscription plan.' Issue: --------------------------------------- When you manually add a line and click 'Save', the constraint (`_constraint_subscription_plan`) is triggered and raised `UserError` https://github.com/odoo/enterprise/blob/434d88960abb5e424fdc1106fc93935d328bff78/sale_subscription/models/sale_order.py#L176-L177 When you add a product via the catalog view, it calls `_update_order_line_info` which directly creates/updates order lines, Which do not trigger the python constraint. https://github.com/odoo/odoo/blob/ef9772bba1515bdaf5410c3af5a3e395f562d513/addons/sale/models/sale_order.py#L1926-L1933 Solution: --------------------------------------- Two private helpers are introduced: * `_is_exempt_from_subscription_plan_check`: single source of truth for all exempt states (draft, cancelled, upsell, and legacy upgrade orders). * `_check_recurring_plan_mismatch`: raises a `UserError` when the order has or will have a recurring product but no subscription plan, reusing the exemption helper so both call sites stay in sync. `_constraint_subscription_plan` is refactored to delegate to these helpers, and `_update_order_line_info` is overridden to call `_check_recurring_plan_mismatch` before the catalog update is applied, ensuring consistent validation across both entry points. opw-6194865 Forward-Port-Of: odoo/enterprise#122253 Forward-Port-Of: odoo/enterprise#117879
Pasting document links into an empty message no longer adds an unnecessary blank line at the start. Existing text still stays separated from pasted links, keeping messages neat without changing the workflow.
Original PR description
Before this commit, adding document links always prepended a line break before the generated links. When the composer was empty, this resulted in messages starting with an unnecessary blank line. This commit only inserts a line break when the composer already contains text, avoiding the extra spacing while preserving the separation between existing content and pasted links. task-[5947683](https://www.odoo.com/odoo/project/1519/tasks/5947683)
This fix ensures generated website snippets use the correct filter settings regardless of the order in which modules were installed. It helps prevent website content blocks from showing incorrect or broken dynamic content for customers with different installation histories.
Original PR description
Our default dynamic snippets filter ids are set based on the order that we install our modules. This can cause issues if the user installs their modules in a different order. To fix this, we need to update the data-filter-id value to the correct value of the DB. To be able to do this, we also change the regex replacement to use lxml instead since it's much simpler. Lxml part from 799f83575e162eb683cfaebb4eb602ccc1fbe466.
Fixed an issue that could block importing Belgian CODA bank statement files after a recent update changed the information returned during parsing. This helps ensure bank statement processing continues reliably for affected Belgian accounting users.
Original PR description
in this commit: https://github.com/odoo/enterprise/commit/c66995fda83e19b28a38312af8efdc1601881cf0 we did a backport of the extension number. The backport adds the extension number to the return of the _parse_bank_statement_file. With that we have 4 args returned. Without the * we would have the "too many value to unpack" error opw-6362679
The website now shows the exact discount configured for subscription pricing when product prices are displayed with tax included. This prevents customers from seeing an incorrect lower discount, such as 4% instead of the intended 5%, improving pricing clarity and trust.
Original PR description
Steps to reproduce: 1. Install eCommerce and Subscriptions. 2. Create a 21% Excluded tax. 3. Create a subscription product with a price of 45 with 21% tax and enable "Accept One-Time" in the…
Steps to reproduce: 1. Install eCommerce and Subscriptions. 2. Create a 21% Excluded tax. 3. Create a subscription product with a price of 45 with 21% tax and enable "Accept One-Time" in the Recurring Prices tab. 4. Publish the product on the website under the Sales tab. 5. Create a pricelist for 6 months recurring with two lines: - If min quantity is 0, then 0% discount - If min quantity is 2, then 5% discount 6. Set "Display Product Prices" to "Tax Included" in the Settings. 7. Open the product on the website, select the 6-month plan, and increase quantity to 2. Issue: The discount percentage displayed on the website shows 4% instead of the configured 5%. Why this happens: In `_get_additionnal_combination_info`, the discount is reverse-calculated from the tax-included price vs the tax-included sales price. When the 21% tax is included to both prices, it introduces a floating-point precision loss (4.9954..%), which floor() then truncates to 4%. Fix: When the pricelist rule uses 'percentage' discount, read `percent_price` directly from the pricing rule instead of reverse-calculating from tax-adjusted prices, as it represents the exact discount percentage the merchant configured with no floating-point involvement. opw-6224735