Daily updates from Odoo
Tuesday, August 4, 2026
39 changes · master
Security fixes and vulnerability patches
Employee payroll fields for Swiss, Indonesian, and Turkish payroll are now only accessible to authorized payroll users. This helps protect sensitive payroll information and prevents non-payroll staff from seeing or using these fields.
Original PR description
This commit adds `groups="hr_payroll.group_hr_payroll_user"` to all fields displayed inside payroll tab in the form view of employee to make sure those fields are only accessible to payroll users. runbot-error-234071 Forward-Port-Of: odoo/enterprise#124880 Forward-Port-Of: odoo/enterprise#122293
New functionality added to Odoo
Indian payroll users can now choose ENet as a payment export format and generate the required CSV file from the payroll payment wizard. This makes it easier to prepare salary payment files for banks or payment workflows that use ENet.
Original PR description
This PR adds: - a new `export_format` option as "ENet", and its payment methods - if "ENet" is selected, you can generate ENet CSV using the wizard Task-4585620
The Japanese reporting module now includes statutory Balance Sheet and Profit & Loss statements tailored to local presentation requirements. This helps businesses in Japan prepare required financial reports more directly from their existing chart of accounts setup.
Original PR description
Add the Japanese statutory financial statements (Balance Sheet and Profit & Loss), laid out to the local presentation and driven by the account types and tags from the chart of accounts. task-6271211
Enhancements to existing features
This update makes Odoo's AI assistant more flexible by standardizing how browser-side actions are handled and how results are returned to the AI. It also improves user experience by updating AI thinking messages more dynamically, preserving normal view filters when opening records, and preventing new messages while the assistant is still responding.
Original PR description
Purpose: -------- Instead of handling each AI client tool as a special case when posting a message in the thread, a dedicated registry (ai.client_tools) has been added to make it easy to declare and…
Purpose:
--------
Instead of handling each AI client tool as a special case when posting a message in the thread, a dedicated registry (ai.client_tools) has been added to make it easy to declare and extend client-side tool handlers: `registry.category("ai.client_tools").add(name, (thread, params) => cb);`
On the Python side, AI tools can now trigger client-side behavior by returning a "client_tool" entry with a name and params, keeping the server interface minimal and consistent.
Updating the thinking text is now done using one of this tool, allowing to update the thinking text more dynamically. For example, the thought will now be updated when the web search tool has been executed.
Also, with this commit, the action domains are not overridden anymore: before, if you asked to open your crm pipeline, it would open it without the default hidden domain (type = 'opportunity'). Now, this domain will be applied, so that the view opened is the same as if the user opened it manually.
#### Async JS tools
Client tools can now pause the agent loop, return a result from the
browser and resume the conversation with this result.
By default, client tools wait for a result from the browser. Tools that
do not need to return a result can set `oneway` to true, allowing the
agent loop to continue without creating a pending tool call (for example
to show a notification).
Tool confirmations and client tool results use the same pending tool
response flow. Confirming a tool re-executes it on the Python side,
while returning a client tool result resumes the loop without
re-executing the tool.
To add a tool that allows the agent to get a result from the browser,
one needs to:
- add an AI tool in the backend that returns a dict with a `client_tool`
entry: `'client_tool': {'name': name, 'params': {}}`;
- add an AI tool in the frontend with the same name in the
`ai.client_tools` registry and return the result that needs to be sent
to the LLM.
For a client tool that does not need to return a result, use the `'oneway'`
option on the `client_tool` entry:
`'client_tool': {'name': name, 'params': {}, 'oneway': True}`
To prevent race conditions that could happen when the user sends a new
message while a client tool is being processed, the send button will now
be disabled when the agent is generating a response.
This commit also removes references to `ai_session_identifier` which was
not used anymore.
Task-6352942Improves the process that suggests reconciliation rules when assigning accounts to bank statement lines. The change prevents failures and slowdowns caused by very long payment references, making bank reconciliation setup more reliable for accounting users.
Original PR description
When setting an account to an account.bank.statement there is a step to automatically create a reconciliation rule/model if one does not exist already. To do so, we retrieve 5…
When setting an account to an account.bank.statement there is a step to automatically create a reconciliation rule/model if one does not exist already. To do so, we retrieve 5 account.bank.statement.lines and use them to define the reconciliation model config. A matching is done on the payment_ref of the account.bank.statement.lines by finding the longest common substring in the reference. ### Current Implementation The current algorithm does so by first generating all the possible substrings for all the payment_ref before doing the intersection between these sets and returning the max if `len(substring) >=10`. This is reasonable when the payment_ref follows either a SEPA communication national standard like the Belgian one or the Creditor Reference standard (ISO 11649). For transactions with large, unstructured communication with more than 100 chars, the method `_get_common_substrings` quickly overfill the memory, sometimes raising a MemoryErorr, and takes a significant amount of time. That's because the nested function `_generate_all_substrings` generates n*(n+1)/2 substrings, with n being the lenght of a payment_ref, called `label` in `generate_all_substrings`. ### Proposed Fix This commit introduces another algorithm to find the largest common substring. It starts by taking the two smallest labels to find their substrings intersection. We know that for an arbitrary collection of labels, the intersection of their substrings sets A ∩ B ∩...∩ Z is included in the intersection of any two substrings sets. The underlying assumption of the first step is that for an arbitrary collection of labels the intersection of the substrings sets of the two smallest labels will be the smallest intersection of any given pair of substrings sets. This won't hold true everytime and using a metric such as label similarity instead of shortest string might be better. But on average this should be good enough and it's easier to implement + it removes the need of preprocessing the labels to compute the similarity. The point of the new nested function `common_substrings` is to discard common substrings as we build them. Using the current `generate_all_substsrings` on either the smallest label or both smallest labels would still generate and store a lot of substrings, especially for large labels. By yielding the common substrings as we find them, the memory footprint is vastly reduced. Lastly, the next substring in the common_substrings iterable is only checked against the remaining labels if it's longer than the current match. This speeds up the whole process ### speedup In a customer database with some account.bank.statement.line with payment_ref > 500 chars, setting a specific account (code 4970) on transactions goes from MemoryError to < 1Mb memory consumption. Because of the memory consumption it was not possible to gather timing value on the current version. Testing the new algorithm in a shell and using as labels the 5 longest payment_ref in the customer database (831, 831, 1117, 1178, 1300 chars), averaging to 2000 chars once normalised, the average time to execute `_get_common_substrings` is 900 ms ± 10.3 ms. Forward-Port-Of: odoo/enterprise#121575 Forward-Port-Of: odoo/enterprise#118824
The website builder now shows a proper preview image for the AI live chat snippet, even when live chat is not installed. Users can also preview the fallback contact button on hover, making the editing experience clearer and more consistent.
Original PR description
*:ai_website_livechat Problems: 1) There's no preview of the livechat snippet in the website builder. If ai_website is installed but not livechat, there's no preview image for the snippet resulting in a cluttered and inconsistent UX. 2) There is no preview on hover for the livechat preview button. Unlike other odoo builder options, the user cannot see what the livechat preview button would look like if hovered over. Solutions: 1) An image has been added `ai_livechat.png` which is shown on preview 2) The AI livechat fallback is previewable and defaults to "Contact Us" linking to the /contactus page. Task-5248712
The timesheet ActivityWatch suggestions panel now displays total tracked time by project and an overall total at the bottom. This gives users a clearer view of how much time has been captured before creating or reviewing timesheets.
Original PR description
This commit introduces new time tracking metrics to the ActivityWatch suggestions panel to improve user visibility into their tracked hours. **Enhancements:** - Added the total duration per project in the By Project grouped view. - Added a grand total footer for all suggestions at the bottom of the list. task-6088877 Forward-Port-Of: odoo/enterprise#125515 Forward-Port-Of: odoo/enterprise#114772
This update aligns several country-specific Point of Sale accounting and electronic invoicing flows with recent accounting changes. It helps keep POS receipts, fiscal certification, and tax reporting working correctly across affected localizations after the accounting refactor.
Original PR description
Refector PR: https://github.com/odoo/enterprise/pull/112634
Shop floor users can now manually adjust production time logs when a timer was not started or stopped correctly. This helps keep work order timing accurate by creating or closing time entries based on the corrected time.
Original PR description
The "Update Time Log" dialog inside shopfloor is added to increase the timer's reliability by manually entering the desired time. If someone forgot to start the timer, this option adds a new productivity line ending now. If someone forgot to stop it, this option close the timer and set the end date accordingly. Task-6164336
When an item quantity is set to zero in the certified Point of Sale flow, all removed order lines are now visibly struck through, not just weighted products. This improves receipt and order clarity and prevents newly added items from being incorrectly merged with previously removed lines.
Original PR description
We now strike every orderline instead of only the ones related to weightable products, when quantity is set to 0. We also fix an issue where the PoS kept merging new orderlines with strikedthrough ones. task-6425588
Cashiers can now see each customer's due or deposit amount directly on the mobile customer selection card. This makes it easier to spot outstanding balances or available deposits before choosing a customer, speeding up checkout decisions.
Original PR description
This commit adds the customer's due/deposit amount to the customer card displayed in the mobile customer selection list, allowing cashiers to quickly identify outstanding balances or available deposits when choosing a customer. Task-6329233 Related PR: https://github.com/odoo/odoo/pull/272076 <img width="200" height="431" alt="image" src="https://github.com/user-attachments/assets/d4ad9e0a-34f9-4995-84d3-8c28058cba4f" />
This updates internal tests for the rental website planning feature to match recent Google Analytics 4 tracking behavior. It helps keep automated checks reliable when analytics tracking is enabled, with no expected change for day-to-day users.
Original PR description
`tracking_info` is now only computed when `google_analytics_key` is set, and `item_id` now uses the template id as a string rather than the variant id as an integer. Set the key in `setUpClass` and update assertions accordingly. See : - https://github.com/odoo/odoo/pull/253856
The manufacturing work order display was slightly simplified by moving an internal setting to the main screen component instead of sharing it more broadly. This reduces unnecessary internal complexity without changing how users interact with the feature.
Original PR description
This commit removes localStorageName from env. It was added in the env but never used in child components so it can be set on the root component.
HR users can now complete employee document signature requests themselves when they are the only required signer. This removes the unnecessary step of sending the document to the employee, saving time and simplifying the process.
Original PR description
Before:
- When creating a Signature Request from the employee form:
- If the document had only one signer (HR user), the system still asked to
send it to the employee.
- HR users could not sign the document directly.
After:
- If there is only one signer (the HR user):
- The HR user can now sign the document directly.
- No need to send the document to the employee.
Impact:
- Saves time for HR users.
- Makes the process simpler and faster.
- Reduces unnecessary steps.
Task: 6032364Resolved issues and error corrections
Restored automated checks for online payment flows in self-order and kiosk preparation display scenarios. This helps ensure payment journeys continue to work correctly and reduces the risk of regressions reaching customers.
Original PR description
The four online payment preparation display tests were skipped because their tour never reached the online payment step. - Register the tour, and the `pos_self_order` tour utils it imports, in `web.assets_tests`. The tour leaves the self-order SPA for the `/pos/pay/<id>` payment portal page, where only the frontend bundle is loaded, so without this the tour is gone from the registry as soon as the page is unloaded. - Make the "Pay" step use `expectUnloadPage: true` and wait for the payment portal submit button, so the tour actually reaches the payment page instead of ending on the self-order page. - Use the `test_online_payment_kiosk_qr_code` tour for the two kiosk tests, which stay in the kiosk and check the QR code. - Unskip the four tests and move their duplicated setup into a kiosk and a self-order helper. task-id: 6244255
The Timesheet Assistant no longer suggests calendar events marked as available. This keeps recommendations focused on events that may need timesheet entries and reduces distractions for users.
Original PR description
## Previous Behavior In the Timesheet Assistant view, calendar events marked as *available* were still being suggested. These events are not intended to be timesheeted and should not appear in the assistant’s recommendations. Their presence could also obscure more relevant events that require user attention. ## New Expected Behavior Calendar events marked as *available* are now excluded from Timesheet Assistant suggestions. task-[6431591](https://www.odoo.com/odoo/project/4105/tasks/6431591) Forward-Port-Of: odoo/enterprise#126183
The expense Stripe cardholder field now uses the standard setup for selection fields, ensuring filters defined in the view are applied correctly. This prevents users from seeing or choosing inappropriate cardholder records when managing expense card details.
Original PR description
After https://github.com/odoo/odoo/issues/196785; the standard way to build a custom m2o field in JS is to call a method from the Many2one module, instead of extending an object from it. This commit solves issues regarding domain in the view not being passed to the widget opw-6399906 Forward-Port-Of: odoo/enterprise#125346
This change corrects how Timesheet Grid recognizes Discuss-related rules so notification count badges do not interfere with matching. It helps ensure the intended automation or guidance continues to work reliably when users have unread notifications.
Original PR description
task: 6416889 Forward-Port-Of: odoo/enterprise#125877 Forward-Port-Of: odoo/enterprise#125519
The Field Service planning map now checks assignments more reliably before showing the routing popup. This prevents errors when planning groups contain unassigned work or translated labels, improving stability for schedulers.
Original PR description
This commit fixes an issue where we search the resources' types in a group's records, possibly not having any resource. Prior to this commit, a condition filtered out the "None" group. However, this causes three issues: 1. The condition does not consider translations (so this would fail for the "None" group in French for instance); 2. If there is any other group than Open Shifts not having resources, this would fail. 3. If there is another group that does not belong to a resource or to Open Shifts that has some records without resources, we should not display the popup. Instead, we dynamically check whether the groupId is part of the resource_ids of *every* group's record in order to display the popup. no-task Forward-Port-Of: odoo/enterprise#126394
Users can now adjust the start or end time of scheduled work orders directly in the Gantt view without triggering an error. The fix also improves handling of dependent work orders, so related scheduling changes continue smoothly instead of failing when a linked item is being moved.
Original PR description
## Problem When dragging the edge of a scheduled workorder to change the start or end time, _web_gantt_move_candidates would throw a traceback. This is because the web call only supplies the new time…
## Problem When dragging the edge of a scheduled workorder to change the start or end time, _web_gantt_move_candidates would throw a traceback. This is because the web call only supplies the new time chosen by the drag+drop. That is, if date_end was changed, date_start wouldn't be present, so accessing the missing field directly triggers a KeyError. This also revealed a secondary issue involving dependent tasks, where if the parent task is rescheduled with the pills, the child task would fail to find candidate reschedule dates (since its only dependency is being moved), and no boundary date would be supplied when calling _web_gantt_reschedule_compute_dates. This led to another traceback. ## Solution For the first issue, we will get the start date and end date from the supplied values more safely, using get() to default to the original start/end. For the second issue, if the boundary date isn't found by _web_gantt_get_first_and_last_possible_dates, we fall back to the candidate's existing start or end date. ## Steps to replicate (Runbot saas-19.4) 1. Create a product with a BOM with 2 operations on the same workcenter 2. Create an MO for this product, confirm it, and plan it 3. Head to Manufacturing > Planning > Work Orders / Planning 4. Try to change the end date of the first work order by dragging the edge of the pill opw-6378769 Forward-Port-Of: odoo/enterprise#124710
The printer selection popup now correctly limits choices to printers assigned for the report. This helps users choose the right printer and avoids accidental printing to unrelated devices.
Original PR description
This commit fixes the domain for the printer selection popup when printing a report. The assigned printers were not taken into account. task-6332442 Forward-Port-Of: odoo/enterprise#122404
The timesheet assistant now keeps its suggestions aligned with the date the user most recently selected, even when switching dates quickly. This prevents outdated suggestions from another day appearing due to delayed background requests.
Original PR description
Before this commit, when the user hits multiple times the arrow button to change the date displayed in timesheet assistant, the suggestions displayed could be the suggestions from another day because a rpc is made each time the user changes the date and amoung all rpcs call, the one which takes more time then the one will be taken but it is not necessary the date shown in the view. This commit uses `KeepLast` class to avoid the concurrency issue with those rpcs to be able to always take the last rpc call to get the data. Forward-Port-Of: odoo/enterprise#126323 Forward-Port-Of: odoo/enterprise#126283
Guatemalan electronic invoice PDFs now match the tax information used in the official XML file. This prevents mismatches when customer tax IDs are missing or placeholder values are used, and applies the legal threshold consistently across currencies.
Original PR description
with this commit:- - Display 'CF' in the invoice PDF whenever the generated XML uses CF. - Treat placeholder VAT values such as '/', 'NA', and 'na' as missing VAT. - Compare the invoice total using the company currency instead of the document currency when evaluating the 2,500 threshold, ensuring the legal limit is applied consistently regardless of the invoice currency task-6305333 Forward-Port-Of: odoo/enterprise#120985
This fix lets regular invoicing users post invoices or reset them to draft when Avalara tax integration is enabled. It removes an access-related blocker so day-to-day invoice processing does not require administrator intervention.
Original PR description
The field `avalara_connection_method` has a restriction to only admins, but needs to be read by normal invoicing users in order to post or reset invoices to draft. Forward-Port-Of: odoo/enterprise#126464
This fix prevents an error when creating a Hong Kong payslip for an employee whose contract start date is missing. Payroll users can now select the employee and continue payslip preparation without the system crashing, while existing handling for missing dates remains in place.
Original PR description
Currently, an error occurs when a user sets an employee on a payslip. **Steps to Reproduce:** - Install `l10n_hk_hr_payroll` with demo data. - Switch to the `Hong Kong` company. - Create an…
Currently, an error occurs when a user sets an employee on a payslip. **Steps to Reproduce:** - Install `l10n_hk_hr_payroll` with demo data. - Switch to the `Hong Kong` company. - Create an `employee` and make sure that the employee's version has no `contract start date`. - Go to `Payroll` > `Payslips` > `Payslips`. - Create a `payslip` and set that employee. `TypeError: '<' not supported between instances of 'datetime.date' and 'bool'` When a user sets an employee on a payslip, the system computes the worked day lines [1]. If the salary structure uses worked day lines, it creates the corresponding records [2] and calculates out days and out hours based on the contract dates. During this process, the payslip dates are compared with the version's contract start date. If the version does not have a contract start date, it raises an error [3]. This commit ensures that the payslip dates are compared with the version's contract start date, and that out days and out hours are calculated only when the contract start date exists. Cases where no contract start date is defined are already handled in payslip [4]. [1]: https://github.com/odoo/enterprise/blob/03787659236cbcb46c27acebf410ee3d1e9eb15c/hr_payroll/models/hr_payslip.py#L1964 [2]: https://github.com/odoo/enterprise/blob/03787659236cbcb46c27acebf410ee3d1e9eb15c/hr_payroll/models/hr_payslip.py#L1985-L1988 [3]- https://github.com/odoo/enterprise/blob/03787659236cbcb46c27acebf410ee3d1e9eb15c/l10n_hk_hr_payroll/models/hr_payslip.py#L309 [4]- https://github.com/odoo/enterprise/blob/03787659236cbcb46c27acebf410ee3d1e9eb15c/hr_payroll/models/hr_payslip.py#L1092-L1096 sentry-7632216317 Forward-Port-Of: odoo/enterprise#120234
Quotations created from repair orders linked to helpdesk tickets now automatically use the salesperson assigned to the customer. This prevents missing salesperson information, helping sales ownership and follow-up stay accurate.
Original PR description
Currently, when a quotation is created from a repair order generated from a helpdesk ticket, the salesperson is not set on the quotation even if the customer has a salesperson assigned. **Steps to…
Currently, when a quotation is created from a repair order generated from a helpdesk ticket, the salesperson is not set on the quotation even if the customer has a salesperson assigned. **Steps to Reproduce:** - Install `helpdesk_repair`. - Go to `Helpdesk` > `Configuration` > `Helpdesk Teams`. - Open a team recod and enable `Repairs`. - Create a `contact/customer` with a `salesperson` assigned. - Go to `Helpdesk`, create a ticket for that `customer`, and select the `helpdesk team` configured above. - Click `Repair`, then click `Create Quotation`. - Open the quotation and check the `Salesperson` field in the `Other Info` tab. **Current behavior:** The Salesperson field on the quotation remains empty. **Expected behavior:** The Salesperson field on the quotation should inherit the salesperson assigned to the selected customer/contact. **Cause of the issue:** When a repair order is created from a helpdesk ticket, default_user_id [1] is passed in the context . This value is propagated when creating the repair order [2] . Later, when creating the quotation from the repair order [3], the same context is reused. Because default_user_id is already present in the context, it overrides the precomputation of user_id from the customer. As a result, user_id is initialized with an empty value and remains unset. **Fix:** This commit ensures that default_user_id is removed from the context before creating the sale order. Without a default value for user_id, the field is correctly precomputed from the selected customer, and the salesperson is properly assigned. [1]- https://github.com/odoo/enterprise/blob/2662932c7ac8ebf3ed5a05d44d7ebfaff869fcbd/helpdesk_repair/models/helpdesk_ticket.py#L52 [2]- https://github.com/odoo/enterprise/blob/2662932c7ac8ebf3ed5a05d44d7ebfaff869fcbd/helpdesk_repair/models/helpdesk_ticket.py#L36-L40 [3]: https://github.com/odoo/odoo/blob/29328b8fccff833c14de317b51f3b4e5a8c40f75/addons/repair/models/repair.py#L357 opw-6344939 Forward-Port-Of: odoo/enterprise#126310 Forward-Port-Of: odoo/enterprise#122980
The Argentine electronic invoicing test setup was adjusted so a live currency-rate check is not run during daily builds that block external web requests. This prevents avoidable build failures while still allowing the check to run in nightly testing with the right access.
Original PR description
Description of the issue this commit addresses: The live ARCA currency rate test keeps the inherited `standard` tag. It is therefore selected by daily builds whose HTTP guard blocks the request. The guard also blocks it when selected by the external localization suite. --- Desired behavior after this commit is merged: This commit removes the `standard` tag from the live ARCA test. Daily builds skip the test while nightlies still run it with HTTP access. --- runbot-[238857](https://runbot.odoo.com/odoo/error/238857) Forward-Port-Of: odoo/enterprise#125692
Date and date-time fields are now hidden from the column selection popover once they have already been added, just like other fields. This prevents duplicate columns from being created and avoids inconsistent spreadsheet behavior for users configuring list views.
Original PR description
Current behavior before PR: - Date and datetime fields remained visible in the popover after being added as columns, allowing the same field to be added multiple times. - Since column fields do not consider granularity, allowing duplicate date fields could create duplicate IDs and inconsistent behavior. Desired behavior after PR is merged: - Treat date and datetime fields the same as other column fields when determining which fields to display in the popover. - Once a date or datetime field is added as a column, it is no longer shown in the popover to prevent duplicate IDs. Task: [6295794](https://www.odoo.com/odoo/project/2328/tasks/6295794) Forward-Port-Of: odoo/enterprise#123463
Internal CRM users can once again create leads from business card pictures without needing administrator rights. The change keeps access checks for actions tied to specific records while allowing the business card option when the related app is available.
Original PR description
**Steps to reproduce:** - Go to CRM app as an internal user (non-admin) - Click on Generate button - Can't create leads from business card pictures - Only setting the user as admin enables it (was…
**Steps to reproduce:** - Go to CRM app as an internal user (non-admin) - Click on Generate button - Can't create leads from business card pictures - Only setting the user as admin enables it (was working fine in previous versions) **Issue:** Dropdown action is restricted to admin only by default using `hasAccess`. If there is a corresponding model on the `LeadGenerationDropdown` it is later changed according to the current user access rights using `await user.checkAccessRight(model, "create")`. **Fix:** Default `hasAccess` to `True` as there is no related model for the lead generation of business cards. (Note: could also provide the missing model ?) - Installation should be restricted to the admin. - Access message should be shown to the user if he doesn't have enough rights to the related model. - Non-admin users should be able to use the feature if no model is provided and the related app is available. dropdown: https://github.com/odoo/odoo/commit/978019522746ccb971eeb15c5d9530e438b7d2f3 business card: https://github.com/odoo/enterprise/commit/48a9cba24cb51b11a08dd9c0ff1291e15232260f opw-6258689 Forward-Port-Of: odoo/enterprise#121682
Restaurant orders using the German Fiskaly POS certification now show on the Kitchen Display as soon as the first item is added. This prevents kitchen staff from missing or delaying newly created orders in affected German POS setups.
Original PR description
**Step To Reproduce:** 1. Configure a POS with German Fiskaly (l10n_de_pos_cert), Restaurant, and Kitchen Display (pos_preparation_display). 2. Create a new order in the POS and add the first…
**Step To Reproduce:** 1. Configure a POS with German Fiskaly (l10n_de_pos_cert), Restaurant, and Kitchen Display (pos_preparation_display). 2. Create a new order in the POS and add the first product. 3. Observe that the order does not appear on the Kitchen Display. 4. Add a second product to the same order. 5. Observe that the order now appears on the Kitchen Display. **Issue:** The first product of a new restaurant order is not synchronised with the Kitchen Display when the German Fiskaly localisation is enabled. **Reason:** `syncAllOrders()` only processes orders returned by `getPendingOrder()` and ignores orders explicitly passed through `options.orders`. After the initial Fiskaly synchronisation, the order is serialised and removed from the pending queue. Consequently, the Preparation Display synchronisation receives no orders from `getPendingOrder()`, preventing the order from reaching the backend. **Solution:** Update `syncAllOrders()` to prioritize the orders explicitly provided through `options.orders`. When `options.orders` is not available, fall back to the existing behavior by synchronizing the orders from `orderToCreate` and `orderToUpdate`. opw-6321376 Forward-Port-Of: odoo/enterprise#125743
This fix makes automated tests for assigning planning resources more stable by avoiding timing-related selection mistakes. It helps reduce false test failures, supporting smoother validation and delivery of Planning field service changes.
Original PR description
This commit fixes undeterministic failures in the `many2many_avatar_resource` tests. Previously, resources were added by typing its name, waiting for the list to update and clicking on the resource. However, `edit` auto-completes with some delay, thereby resulting in random errors where the first resource from the list was added. Instead, we let the `edit` autocomplete to run in order to add a resource, ensuring the first resource from the list is not added as a consequence. runbot-error-941174 Forward-Port-Of: odoo/enterprise#126482
The Belgian payroll rules for CP302 eco-vouchers have been corrected so employees receive prorated voucher amounts based on the proper treatment of full-time, part-time, partial-year work, public holidays, and unpaid absences. This helps payroll teams apply sector rules more accurately and reduces the risk of incorrect employee benefits.
Original PR description
Per the CP302 rules:
- Full-time, incomplete year: 250 × complete_months/12 + 250 × working_days/divisor for any partial month at start/end.
- Part-time: 250 × working_days/divisor. Days are counted as-is ("each daily service = 1 day regardless of duration"), so work_time_rate is not applied to the day count.
- Divisor: 260 (5-day week) or 312 (6-day week).
- Working days use `get_work_duration_data(compute_leaves=False)` so public holidays stay assimilated; only unpaid absences are deducted.
task-6375105
Forward-Port-Of: odoo/enterprise#126198
Forward-Port-Of: odoo/enterprise#124297Customers can no longer complete checkout for planning-based rental services when the required resources are already booked. This avoids taking payment for rentals that cannot be fulfilled and prompts customers to choose another date or quantity.
Original PR description
**Problem:** On a website with rental planning enabled, a customer can book a planning-backed rental product through eCommerce even when no planning resource is free for the requested window. The…
**Problem:** On a website with rental planning enabled, a customer can book a planning-backed rental product through eCommerce even when no planning resource is free for the requested window. The cart lets them increase the quantity past the available capacity and proceed all the way through checkout without any availability gate. **Steps to reproduce:** 1. Install `website_sale_renting_planning`. 2. Create a planning role with `sync_shift_rental` and one resource. 3. Create a service product with `rent_ok=True`, `planning_enabled=True` and the role above. 4. Pre-book the resource for some window via a `planning.slot`. 5. From eCommerce, add the product to the cart for the same window. 6. Proceed to checkout/payment. **Current behavior:** The cart is considered ready, no warning is shown, and payment can proceed even though no planning resource is free for the chosen period. **Expected behavior:** The cart should be flagged as not ready and pre-payment validation should refuse to confirm until the customer picks a different date or quantity. **Cause of the issue:** `sale.order._available_dates_for_renting` in `website_sale_renting` is the documented hook for "stock availability" gating of the cart and pre-payment flow (called from `_is_cart_ready` and from `_check_cart_is_ready_to_be_paid`). `website_sale_stock_renting` overrides it to apply a per-line stock check, but `website_sale_renting_planning` has no such override, so planning-backed rental services reach payment with no availability gate at all. **Fix:** Apply the same gating pattern that `website_sale_stock_renting` already uses: override `_available_dates_for_renting` in `website_sale_renting_planning` so that, for each rental line whose product is a planning-synced rentable service, the cart is only considered valid when at least the requested quantity of planning resources is free during the rental window (mirroring the resource and leave filtering already done by `_planning_slot_vals_list_per_sol` at SO confirmation time). This puts the gate at the same point the stock-renting flow enforces it, keeping the public cart/checkout flow consistent across rentable product types. opw-6247034 Forward-Port-Of: odoo/enterprise#125855 Forward-Port-Of: odoo/enterprise#118943
This fixes how Indian reports classify transaction types for journal entries, especially Point of Sale entries that use general journals. Existing databases are also updated so past entries use the corrected classification logic.
Original PR description
Description: In #118297 non-sales journal moves were considered purchase moves during l10n_in_transaction_type computation, which is not correct for POS moves as their journal is of type 'general'. Fix: Compare only the purchase journal moves state against the partner state. Other moves treated as sales and their state compared against the company state. Add a migration script to update existing databases. opw-638646 Forward-Port-Of: odoo/enterprise#125697
This fix makes Dominican Republic 606 report tests use a consistent document setup instead of depending on which optional modules happen to be installed. It also stabilizes reversal dates, reducing false test failures and helping keep report behavior reliable for customers using either configuration.
Original PR description
Whether DO journals use LATAM fiscal documents depends on `l10n_do_edi` being installed: it is what supplies the `_localization_use_documents` override for DO. l10n_do_reports doesn't depend on it, so the tests inherited whichever configuration the build happened to install, and only went red on the per-module build. Without the EDI module the reversal's `ecf_34` document type produced the name "E34 B0400000001", which the yearly sequence regex reads as year 34; checked against a 2024 date, the sequence constraint rejects it on post. Pin the flag explicitly instead, and run the assertions against both configurations, since customers run both: the NCF is read off the fiscal document number with e-CF, and off the reference without it. Also pin the reversal's accounting date. Left out, `_get_accounting_date` pushes it to the end of the month once the invoice date is in the past, which made the test depend on the date it ran. runbot-error-944488
Accounting report snapshots now store the correct cutoff date for lines that look back to the start of a period or fiscal year. This prevents reports such as balance sheets from silently omitting transactions after a company lock date, improving accuracy for previously affected financial reports.
Original PR description
Once a lock date is set on a company, report lines that look back before a given date, such as a Balance Sheet's "Profits (Losses) from Previous Years", could silently lose data. Any line that gets…
Once a lock date is set on a company, report lines that look back before a given date, such as a Balance Sheet's "Profits (Losses) from Previous Years", could silently lose data. Any line that gets captured in a snapshot and uses a date scope 'to_beginning_of_*' was affected. Snapshots are computed on the options of the lock date and stored with their 'date' set to the options' date_to (the lock date). Only 'from_beginning' actually evaluates the accounting up to date_to. The 'to_beginning_of_*' scopes stop right before the period or fiscal year, so the data really aggregated stops earlier than the stored date: - 'to_beginning_of_fiscalyear': up to a whole fiscal year earlier. - 'to_beginning_of_period': up to a whole period earlier. When the report is rendered, the engine sums only the moves dated after the snapshot's date and adds the snapshot's data. Everything between the snapshot's real cut-off and its (later) stored date is never counted. Aim the options at the lock date so each scope's bound falls on it, and store the date really covered(using _get_date_bounds_info()). The snapshot's date then always matches its data, and "to_beginning_of_*" covers the last fiscal year starting before the lock date instead of forcing every later render to rescan it. Snapshots written before this fix still hold the mismatched date, so the account_codes sub-engine version is bumped to 2 to re-trigger the snapshots generation opw-6379956 Forward-Port-Of: odoo/enterprise#126542
Code cleanup and technical improvements
The VOIP audio manager now tracks changes to call and audio settings in a cleaner way, ensuring observers are properly cleaned up when no longer needed. This reduces the risk of hidden background work building up over time without changing the user-facing calling experience.
Original PR description
Enterprise counterpart of "[REF] mail: drop the onChange queue for owl effects", which explains the API. Before this commit, the audio manager observes three fields by name and drops the dispose function each observer returns, so nothing ever stops those observers. This commit turns the three observers into dependency lists on the rtc and settings records, keeping `initialRun: false`: the refresh at the end of setup does the initial sync. The records dispose these observers. The audio manager tests take the real store: a fake store has no record to observe. One of them counted the calls to `enumerateDevices` to know that the status was refreshed, and with the real store there are two audio managers, the one of the voip service and the one the test builds, both enumerating the devices. That test counts the refreshes of its own manager instead. https://github.com/odoo/odoo/pull/279818
This update renames internal enrollment-related campaign fields to make their purpose clearer and easier to maintain. It also adds safeguards around the enrollment uniqueness field so future campaign setup is more reliable, with no intended change to user-facing behavior.
Original PR description
In order to ease understanding, prepare future changes and ease grep through code, rename enroll-specific fields on campaign model * domain -> enroll_domain * unique_field_id -> enroll_unique_field_id No functional change should come with this PR. Task- Prepares Task-
VoIP configuration such as credentials, device number, and do-not-disturb timing is now read from the dedicated user settings record instead of a mixed local settings area. This aligns VoIP with the newer settings structure, making preferences clearer and easier to maintain without changing the visible user experience.
Original PR description
Before this commit, the voip columns of res.users.settings were read off store.settings, the record that mixed the server row with the local preferences of the device. Reminder that the mail counterpart of this commit splits the two: res.users.settings becomes a record of its own, reached from its owner, store.self_user.res_users_settings_id, and store.settings keeps only the local preferences. This commit declares the voip columns on that record, sends them through _store_settings_fields, and reads a credential, the device number and the do-not-disturb time off it. Note that the field declarations sit in core/common, reachable from every bundle, while the behavior stays in core/web. https://github.com/odoo/odoo/pull/279128