Sunday, September 13, 2026
19 changes · master
New functionality added to Odoo
Internal users can now record Discuss calls and access recordings later from the call history. This helps teams preserve important conversations, revisit decisions, and share meeting context more easily.
Original PR description
Allow internal users to record Discuss calls and replay them from call history. Co-authored-by: Louis Wicket <wil@odoo.com> security: > PY022 x2 @ addons/mail/controllers/discuss/rtc.py csrf=False…
Allow internal users to record Discuss calls and replay them from call history. Co-authored-by: Louis Wicket <wil@odoo.com> security: > PY022 x2 @ addons/mail/controllers/discuss/rtc.py csrf=False and cors="*" are used to allow this route to be used in cross-origin (from the SFU), using a JWT signed by a shared secret for authentication. (see [in the SFU PR](https://github.com/odoo/sfu/blob/master-recording2-tso/src/recording/models/media_uploader.ts)) > PY005 x3 @ addons/mail/tools/jwt.py using hmac/hashlib to implement the JWT verification method, used for SFU request authentication, added tests for the JWT implementation at `addons/mail/tests/test_mail_jwt.py` since the signing part was already introduced for push notifications and [SFU client authentication](https://github.com/odoo/odoo/pull/145633/changes#diff-522341c069d4ea6b162fd1e7ac8ee8b7b94941e18664dea5f7147624a1281d3c). related to: https://github.com/odoo/enterprise/pull/125660 sfu: https://github.com/odoo/sfu/pull/27 [task-3725174](https://www.odoo.com/odoo/project.task/3725174)
Adds maintenance contract support to subscriptions so delivered serial-numbered equipment can be tracked as maintained. Business users can see which serial numbers are covered, access related subscriptions from equipment records, and have field service warranty status reflect subscription coverage.
Original PR description
- Create `Maintenance Contracts` option that enable contracts in the subscriptions - Create a `lot_ids` field that records SNs in the `sale.order.line` - Fill `lot_ids` with the delivered SNs - Make a 'Maintained' ribbon to the serial number - Make a `Subscriptions` stat button in `stock.lot` form view - Add `Maintained` indicator to list and kanban views - Update `under_warranty` if shift is part of a subscription --- task-5184421
Enhancements to existing features
Online payment screens now reflect when a payment is under audit in OdooFin, so users can see why online payment options may be unavailable. This helps avoid confusion by hiding or disabling payment actions that cannot be used during the audit process.
Original PR description
Sometimes payments can be in audit on odoofin, in this case the payment online option is disabled. This commit connects the audit status on Odoofin and display or hides some elements on the interface according to thse audit status. task-6495163
Resolved issues and error corrections
Switching to another view via Ask AI while a full email composer is open no longer triggers an error after the original record view is closed. This avoids a disruptive warning for users and keeps navigation smooth when moving between CRM and other views.
Original PR description
Asking the AI agent to navigate to a different view calls doAction with clearBreadcrumbs, which tears down the current form view (and its chatter) before the still-open full mail composer dialog is…
Asking the AI agent to navigate to a different view calls doAction with clearBreadcrumbs, which tears down the current form view (and its chatter) before the still-open full mail composer dialog is closed. Closing that dialog then calls the chatter's onCloseFullComposerCallback, which reloads the parent record through reloadParentView(). However at that point the chatter no longer exists, so the reload's RPC call gets rejected with "Component is destroyed", and nothing is left to catch it.
How to reproduce:
- Open "Ask AI" from the top bar.
- Open an opportunity in CRM, then open the mail composer (click either 'Send message' or 'Log Note'), then click the enlarge button so it opens as a full composer dialog.
- Ask the agent (the one you pre-opened) to open another view, e.g. "show me all my contacts in the US", "show me the contact view of Abigail Peterson"
Current behavior:
The requested view opens correctly, but an UncaughtPromiseError ("Component is destroyed") is raised.
Expected behavior:
Switching views while a full composer dialog is open should not raise any error. The chatter's parent record should simply not be reloaded if the chatter has already been destroyed by the time its full composer dialog closes.
community: https://github.com/odoo/odoo/pull/287125
task: 6365003
Forward-Port-Of: odoo/enterprise#131279
Forward-Port-Of: odoo/enterprise#131112Belgian payroll now uses clearer establishment unit wording and adds checks to prevent payroll issues when employee contracts fall outside an establishment unit's valid location period. It also streamlines setup by auto-filling competences from working addresses and making employee access from establishment units easier.
Original PR description
1. Renamed DMFA work locations into Establishment unit 2. Added checks to make sure employees don't start their contract before the location period of an establishment unit 3. Added a warning on Payroll, blocking payslips if the establishment unit location date isn't correct 4. Added automatic completion for competences: when selecting a working address, the competence is filled automatically. 5. Added a smart button 'Employee' on Establishment unit. __ task-6432041
Belgian payroll now uses clearer establishment unit naming and adds stronger checks around employee contract dates and work locations. This helps prevent payroll processing errors, improves automatic data completion, and makes it easier to find employees linked to each establishment unit.
Original PR description
1. Renamed DMFA work locations into Establishment unit 2. Added checks to make sure employees don't start their contract before the location period of an establishment unit 3. Added a warning on Payroll, blocking payslips if the establishment unit location date isn't correct 4. Added automatic completion for competences: when selecting a working address, the competence is filled automatically. 5. Added a smart button 'Employee' on Establishment unit. 6. Added address_id as required field. 7. Prevent autofill on l10n_be_hr_payroll when there are multiple establishment units for the same company. __ task-6432041
Expense report PDFs are now generated in grouped batches where possible instead of separately for each expense. This preserves the previous expense sheet reporting behavior and should make report generation more efficient and consistent for users handling multiple expenses.
Original PR description
Since 704a5a19, the reports would be rendered once per expense. We actually want to group expenses as much as possible and keep the logic of the late expense sheet PDF generation. task-5951683 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Expense reports linked to payroll are now grouped together where possible instead of being generated one expense at a time. This keeps the previous expense sheet reporting behavior and should make payroll expense report handling more efficient and consistent.
Original PR description
Since odoo/odoo@704a5a19, the reports would be rendered once per expense. We actually want to group expenses as much as possible and keep the logic of the late expense sheet (RIP) PDF generation. task-5951683
Bank statement lines can now automatically reconcile installment-based accounting entries when the system is confident they are linked. When multiple installments are involved, the earliest installment is processed first, helping reduce manual reconciliation work and improve consistency.
Original PR description
Moves with installments should be auto reconciled if we're sure the move is linked to the statement line. If we are sure that the installments are linked to the statement line then the installment with the lowest id should be reconciled first. task-6285410 Forward-Port-Of: odoo/enterprise#131304 Forward-Port-Of: odoo/enterprise#119891
The Belgian CODA Clean import process now records clearer log information when importing CODA bank files. This helps support teams investigate import issues faster without changing the user workflow.
Original PR description
This commit will improve the logs of _l10n_be_codaclean_import_coda_files to help the support team to debug possible problem. task-5436868 Forward-Port-Of: odoo/enterprise#131258 Forward-Port-Of: odoo/enterprise#129854
Users can now point the website AI assistant to a specific page element instead of describing it in words. This makes edit requests clearer on complex pages and helps the assistant understand targets, references, and insertion points more reliably.
Original PR description
## Element Selection Tool Pointing at an element is much fast than describing it, and text description get ambiguous once a page has repeated or nested structures. Users can now attach an element to a request, whether as the target to edit, a visual reference, or the spot to insert relative to.
Discuss call recordings are now connected to Odoo's AI transcription flow, making transcripts available alongside the recorded media. This helps users review calls more easily, find key discussion points, and follow up without replaying the full recording.
Original PR description
Connect Discuss recordings to the existing AI transcription pipeline so users can review transcripts alongside recorded media. Co-authored-by: ThanhDodeurOdoo <tso@odoo.com> related to: https://github.com/odoo/odoo/pull/234505 https://github.com/odoo/sfu/pull/27 [task-3725174](https://www.odoo.com/odoo/project.task/3725174)
Luxembourg payroll calculations have been updated with the 2026 rule parameters. This helps employers keep payroll contributions, employer rules, general settings, and tax credits aligned with the latest requirements.
Original PR description
Update Luxembourg payroll rule parameters for 2026. Task-6481735 Forward-Port-Of: odoo/enterprise#130123
Appointments can now track guests even when no suitable resource is available, making overbooked or unresolved capacity visible in planning views. For restaurant and appointment bookings, the system can suggest available resources automatically when capacity changes, reducing manual scheduling work while warning users before exceeding normal limits.
Original PR description
### Unassigned Booking Lines A booking line can now have no resource linked to it, representing guests that will attend but for whom we could not find an available resource. These bookings will…
### Unassigned Booking Lines A booking line can now have no resource linked to it, representing guests that will attend but for whom we could not find an available resource. These bookings will appear in the gantt view as a pill in the "unassigned" row so users know they need to do something about that booking. Additionally, a warning is shown at the top of the form in such cases. ### Automatic resource assignment For bookings linked to appointment types that are set as "automatically assign", when the user modifies the "reserved capacity" of an entire event, available resources will automatically be suggested. The suggestion is based around groups of linked resources, attempting to assign resources from the largest groups using the fewest possible resources. This superficially matches what the website would do when automatic assignment is set. If the requested capacity is still too high, a confirmation dialog will appear before saving to let the user know they are exceeding what the system would normally allow. In which case an empty booking line will be created to cover the overcapacity. task-6185278
This fixes an error that could appear when users asked the AI assistant to open another view while a full email composer was still open. Odoo now avoids trying to refresh a record view that has already been closed, so the requested navigation completes without disruptive error messages.
Original PR description
Asking the AI agent to navigate to a different view calls doAction with clearBreadcrumbs, which tears down the current form view (and its chatter) before the still-open full mail composer dialog is…
Asking the AI agent to navigate to a different view calls doAction with clearBreadcrumbs, which tears down the current form view (and its chatter) before the still-open full mail composer dialog is closed. Closing that dialog then calls the chatter's onCloseFullComposerCallback, which reloads the parent record through reloadParentView(). However at that point the chatter no longer exists, so the reload's RPC call gets rejected with "Component is destroyed", and nothing is left to catch it.
How to reproduce:
- Open "Ask AI" from the top bar.
- Open an opportunity in CRM, then open the mail composer (click either 'Send message' or 'Log Note'), then click the enlarge button so it opens as a full composer dialog.
- Ask the agent (the one you pre-opened) to open another view, e.g. "show me all my contacts in the US", "show me the contact view of Abigail Peterson"
Current behavior:
The requested view opens correctly, but an UncaughtPromiseError ("Component is destroyed") is raised.
Expected behavior:
Switching views while a full composer dialog is open should not raise any error. The chatter's parent record should simply not be reloaded if the chatter has already been destroyed by the time its full composer dialog closes.
task: 6365003
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#287877
Forward-Port-Of: odoo/odoo#287125Embedded livechat visitors can now download files sent from Odoo when the chat widget is used on an external website. This fixes a browser blocking issue caused by cross-origin download handling, improving the reliability of customer conversations that include attachments.
Original PR description
**Steps to reproduce:** - Install `im_livechat` module - Copy the code from the livechat channel's widget tab - Paste it in an external website `<head>` (e.g., local python webserver on `0.0.0.0`) -…
**Steps to reproduce:**
- Install `im_livechat` module
- Copy the code from the livechat channel's widget tab
- Paste it in an external website `<head>` (e.g., local python webserver on `0.0.0.0`)
- Start a conversation and send a file from odoo
- Try to download it from the external website
- POST request is sent for the download
- Download fails: `CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.`
- Also when the file is a PDF the preview won't open: `404 (File not found)`
**Issue:**
Mix of multiple issues:
- The download is triggered using a POST request instead of a GET request
(see similar issue for the file viewer [1])
- The file route does not provide the required CORS headers, so requests
originating from the external website are blocked by the browser
- PDF files are rooted to the related path of the `pdfjs` fileviewer
(e.g. `http://0.0.0.0:8000/web/static/lib/pdfjs/web/viewer.html?file=...`)
```xml
<!--
Template rendering all the scripts required to execute the Livechat from an external page (which not contain Odoo)
-->
<template id="external_loader" name="Livechat : external_script field of livechat channel">
<!-- the loader -->
<script defer="defer" t-attf-src="{{url}}/im_livechat/loader/{{channel_id}}" type="text/javascript"/>
<!-- js of all the required lib (internal and external) -->
<script defer="defer" t-attf-src="{{url}}/im_livechat/assets_embed.js" type="text/javascript" />
</template>
```
**Fix:**
Make the `downloadFile` helper handle cross-origin URLs by falling back to a native `<a download>` click (like before) when the target route has the same origin as the embedded script. Could use `session.origin` or `new URL(document.currentScript.src).origin` for this. This is done to avoid allowing CORS on the file content route.
The file viewer issue is handled separately by [1].
For the PDF issue we could manually add the origin to the full url everywhere (but we get some `SecurityError` error from the library due to the cross-origin iframe), add the libjs library in the `assets_embed` (not sure it's possible in `im_livechat.assets_embed_external`), or block external PDF preview for now.
[1] https://github.com/odoo/odoo/pull/281330
opw-6444167
Forward-Port-Of: odoo/odoo#287846
Forward-Port-Of: odoo/odoo#286180Vertical notebook tabs now line up correctly when users open pages that use this layout. Long tab names wrap onto the next line instead of disrupting the page, making the affected dialogs easier to read and use.
Original PR description
When a user opened a page with a vertical notebook, the tabs were not aligned with each other. Vertical notebooks should now have properly aligned tabs. If a tab title is too long, it will wrap onto the next line instead of breaking the layout. task-[5933892](https://www.odoo.com/odoo/project/4105/tasks/5933892) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#287711 Forward-Port-Of: odoo/odoo#279098
Vertical notebook tabs now appear more clearly separated when using dark mode. This makes pages easier to read and navigate, especially where multiple tabs are shown side by side.
Original PR description
## Behavior Before the Commit When a user opens a page with a vertical notebook in dark mode, the different tabs aren't separate from one another. task-[5933892](https://www.odoo.com/odoo/project/4105/tasks/5933892) Forward-Port-Of: odoo/enterprise#131166 Forward-Port-Of: odoo/enterprise#126013
This fixes a rare calendar issue where selecting an undefined partner in the Gantt view could cause the system to crash. The calendar now handles missing attendee information safely, improving reliability for users scheduling or viewing events.
Original PR description
Although it is not usually expected it is technically possible for the value of default partner_ids to be `False`. In which case we don't want to crash.. This can now happen when clicking the "undefined partner" row in gantt. task-6185278