Friday, October 31, 2025
10 changes · saas-18.4
Enhancements to existing features
VoIP sessions now try to sign out automatically when a browser tab is closed and expire sooner if that does not happen. This helps prevent users from hitting provider limits caused by multiple open or recently closed Odoo tabs.
Original PR description
Some providers like OnSIP allow for a limited number of registrations per user. This is a problem in Odoo because each tab opened creates a new registration for one hour. This commit mitigates the problems in two ways: - Sends an "unregister" request onbeforeunload to try to invalidate the registration upon closing the tab. - Reduces the TTL of registrations so that they get invalidated quicker in case the unregistration failed. Forward-Port-Of: odoo/enterprise#98413 Forward-Port-Of: odoo/enterprise#97963
Recruitment screens now load much faster by simplifying how eligible users are determined for job records. This reduces page processing time and response size, making the Recruitment app feel more responsive, especially for companies with many users.
Original PR description
Description ----------- The commit odoo/odoo@0f981b14ea22cc154bcd93f53dc19f46c37ecb13 tried to fix an issue where, if the `company_id` was not set in the Form view, no `user_id` would match if they…
Description
-----------
The commit odoo/odoo@0f981b14ea22cc154bcd93f53dc19f46c37ecb13 tried to fix an issue where, if the `company_id` was not set in the Form view, no `user_id` would match if they had a `company_id` set, while the wanted behavior was the inverse, all internal users should match regardless of companies.
This was fixed by introducing a computed field `allowed_user_ids` which was doing the company computation manually and replaced the `company_ids` domain leaf on the field.
Sadly, this approach introduces a performance regression on the front-end side, as the webclient creates internal data structures *per* individual result of the RHS in the domain. So if `allowed_user_ids` returns a lot of matching `ids`, it becomes a significant overhead.
Following the refactoring of `domains.py`, a slight semantic change happened and the initial issue of the bugfix can be resolved by just changing the domain operator to `'=?'` instead. When `company_id=False`, the domain leaf `('company_ids, '=?', False)` is optimized out by `_operator_equal_if_value` as `_TRUE_DOMAIN` (aka `(1, '=', 1)`). This is as expected behavior post-bugfix. This was not the case before the refactoring.
This allows us to completely deprecate the usage of the field `allowed_user_ids` and the front-end has no significant post-processing to do.
⚠️ This commits deprecates `hr.job.allowed_user_ids`, but doesn't remove it yet, as it might be referenced by views or custom JS.
Benchmark
---------
On a 19.0 database where `allowed_user_ids` returns 1.4k ids, opening the default kanban view of the Recruitment app took:
| | Before | After | Improvement |
|-----------------------|---------|--------|-------------|
| Backend process time | 400ms | 160ms | 2.5x |
| Frontend process time | 3.3s | 220ms | **15x** |
| Total (LCP) time | 3.7s | 380ms | 9.7x |
| Response Payload size | ~800KiB | ~33KiB | **24x** |
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#232354Resolved issues and error corrections
This fixes an issue where live chat operators with standard live chat permissions could not pin a customer's message after a chatbot handed the conversation over to them. The change prevents an unnecessary permission check during message pinning, helping operators manage live chat conversations without errors.
Original PR description
To reproduce (on runbot): - S1: Connect as "admin", leave the "YourWebsite.com" then logout - S1: Connect as "demo" user - S2: As public user, go to /contactus and start a chat session - S2: On the chatbot interaction, choose "I have a pricing question" (this will forward to the operator) - S2: enter a message - S1: On the livechat session, try to pin the last user message Since 1ecddc3d79dd an `AccessError` is raised, as the "demo" user (which is only `LiveChat / User`) don't have access to the chatbot step anymore. As we're not in the interacting with the chatbot when pinning a message, simplify skip that part if there is no "chatbotx answner" context to prevent the `AccessError`. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#233617
Corrects discount rounding for Mexican electronic global invoices so valid invoices are not rejected by CFDI validation. This prevents errors when confirming invoices with percentage discounts and helps ensure compliant invoice generation.
Original PR description
Steps to reproduce: ------------------- * Create an invoice with the following line: * Unit price: 47.25, Qty: 1, Taxes: 16%, Discount 50% * Confirm, create a global invoice > Observation: Error ```…
Steps to reproduce: ------------------- * Create an invoice with the following line: * Unit price: 47.25, Qty: 1, Taxes: 16%, Discount 50% * Confirm, create a global invoice > Observation: Error ``` Code : CFDI40108 Message : El TipoDeComprobante es I,E o N, el importe registrado en el campo no es igual al redondeo de la suma de los importes de los conceptos registrados. ``` Why the fix: ------------ The issue occurs because the `descuento` value, originally 23.625, is now being corrected to 23.615 which leads to `importe` having a value of 23.635 which round up to 23.64 and not 23.63. https://github.com/odoo/enterprise/blob/08564f3312c255f2f3ab95cef5a9bfc57727bd1f/l10n_mx_edi/models/l10n_mx_edi_document.py#L1111 https://github.com/odoo/enterprise/blob/08564f3312c255f2f3ab95cef5a9bfc57727bd1f/l10n_mx_edi/models/l10n_mx_edi_document.py#L1336 Before this commit https://github.com/odoo/enterprise/commit/39759babddc732a312ec5cd6a60a2f1819abc62c the discount value was being rounded when corrected. It would end up being evaluated to 23.62. To not bring back the issue the fixed by the mentioned commit we round the discount when generating the global invoice cfdi values. Now `importe` will have a value of 23.63 as `descuento` is rounded to 23.62. opw-5023597 Forward-Port-Of: odoo/enterprise#95982 Forward-Port-Of: odoo/enterprise#94438
Odoo now blocks deletion of a unit of measure if it is still referenced by a purchase order line. This prevents purchase order confirmations from failing after a unit was removed, improving reliability for purchasing workflows.
Original PR description
When a user deletes the UoM used in a purchase order line and then tries to confirm the purchase order. Steps to reproduce: --- - Install `purchase_stock` module(without demo) - Create a New PO > Add a product in Line (with UoM=Units) - Remove UoM in order line and select `Dozen` in it > Save - Settings > Units of Measure Categories > Open `Units` > Remove `Dozen` - Orders > Requests for Quotation > Open PO > `Confirm Order` Traceback: --- `ValueError: Expected singleton: uom.uom()` `AssertionError: precision_rounding must be positive, got 0.0` This error occurs because, after the UoM is deleted, the `product_uom` field becomes empty, which leads to an error. Solution: --- This commit resolves the error by restricting the deletion of a UoM when it is still in use. sentry-6746792383 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#233783 Forward-Port-Of: odoo/odoo#231478
This fixes an error that could prevent HR users from archiving an employee when they entered a detailed departure reason. The change keeps the departure reason recorded through the existing employee activity log without triggering an unsupported system action.
Original PR description
When archiving an employee with a Detailed Reason, a traceback occurs. Steps to reproduce the error: - Open any employee record > Archive - Set ``Detailed Reason`` > Apply Traceback: ```py…
When archiving an employee with a Detailed Reason, a traceback occurs. Steps to reproduce the error: - Open any employee record > Archive - Set ``Detailed Reason`` > Apply Traceback: ```py NotImplementedError: Unsupported tracking on field departure_description (type html ``` https://github.com/odoo/odoo/blob/8002b82d5783744b88b75c1199c4c1f222a0f7d0/addons/hr/models/hr_version.py#L130 here, ``tracking=True`` was added for the ``departure_description`` html field by the commit [1]. but tracking is not supported for the html field. So, it will lead to the above traceback. Tracking for ``departure_description`` field is already handled via a chatter message in the write method by the commit [2]. https://github.com/odoo/odoo/blob/8002b82d5783744b88b75c1199c4c1f222a0f7d0/addons/hr/models/hr_employee.py#L1187-L1191 [1]: https://github.com/odoo/odoo/commit/aa4d13b89b4497d2e5b33faa49ad86e0788782a2 [2]: https://github.com/odoo/odoo/commit/9b723e2591224f2b563924d3b3dfe27ab909b7d0 sentry-6973440621 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fix prevents negative or incorrect leave durations when Indian sandwich leave rules involve weekends or public holidays. Employees and HR teams now see more accurate leave balances when leave spans non-working days, public holidays, or linked leave requests are changed.
Original PR description
Before this PR, if you created a leave of a type that had sandwich leave enabled on a non-working day, it would show a negative duration. This PR fixes some issues related to sandwich leave cases…
Before this PR, if you created a leave of a type that had sandwich leave enabled on a non-working day, it would show a negative duration. This PR fixes some issues related to sandwich leave cases (where Saturday and Sunday are considered non-working days): - Friday - Monday across weekend - counted (4 days). - Hour-based leave types: weekend bridging increases hours accordingly - Public holiday in the middle (Tue-Thu with Wed PH) - counted (3 days). - Stop/Start exactly on a public holiday(Tue-Wed(Public holiday), or Wed(Public holiday)-Thu) - trimmed to 1 day. - Public holiday only - 0 days. - Two single-day leaves around a Public holiday - When the second leave is created, it bridges via a public holiday (2 days), - The first one remains 1 day if it stands alone - Mixed leave types: - If the linked leave type doesn’t have sandwich enabled, no sandwich rules. - If both leave enable sandwich (with different types) - sandwich rule applies - Refusing/canceling a linked leave must immediately adjust the other side’s duration (e.g., Monday refused - Friday drops from 3 - 1 day) Task-4430044 Co-authored-by: @mepe-odoo Forward-Port-Of: odoo/odoo#233717 Forward-Port-Of: odoo/odoo#193186
Point of Sale users can now search for products whose templates use dynamic attributes, even before a variant has been created. This prevents products from being missed during checkout or sales setup, improving reliability for businesses with configurable items.
Original PR description
Before this commit, it was not possible to search a product that had a dynamic attribute configured on its template, since no product variant was created yet. opw-5188725 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#232838
The Quality Control app now uses much less memory when warehouses open large lists of incoming transfers with many quality checks. This prevents worker crashes and keeps the receiving workflow available for high-volume operations.
Original PR description
The fields `quality_check_todo` and `quality_check_fail` are calculated for stock.picking records by iterating all checks of a stock.picking. This causes a problem when clicking the "To Receive"…
The fields `quality_check_todo` and `quality_check_fail` are calculated for stock.picking records by iterating all checks of a stock.picking. This causes a problem when clicking the "To Receive" button for a warehouse in the inventory app, in case there are many transfers each with many quality checks. The function will default to loading all data associated with quality checks in memory through field prefetching. However, since quality checks have too much data (particularly because of the HTML fields) associated with them, the cache can quickly bloat causing an OOM error and crashing the worker. This PR disables the prefetcher for quality checks before iterating them, preventing this issue from happening since we only need very light fields in the loop. For a specific customer (opw-5025162), this was the case. Benchmarks: | No. stock.picking | avg no. quality checks | peak memory before | peak memory after | | ----------------- | ---------------------- | ------------------ | ----------------- | | 25 | 20 | 2771 mb | 235 mb | opw-5025162 Forward-Port-Of: odoo/enterprise#95568
Italian electronic invoicing no longer blocks valid invoices that include ENASARCO together with a separate withholding tax. The change restores expected behavior for affected Italian invoices while keeping safeguards against invalid tax setups.
Original PR description
In the Italian localization, we validate that each invoice line has at most one tax per kind (VAT, withholding, pension fund). In Italy, a product cannot have more than one VAT tax. Also, the…
In the Italian localization, we validate that each invoice line has at most one tax per kind (VAT, withholding, pension fund). In Italy, a product cannot have more than one VAT tax. Also, the FatturaPA XML structure only allows global declarations for withholding and pension fund taxes — on the line level, it can only specify if those taxes apply, not which ones. To reflect this, we enforce one tax per kind per line. This validation was broken and recently fixed. However, ENASARCO is a special case: it acts both as a withholding and a pension fund tax. We added the Withholding flag recently (odoo/odoo#226968). In realistic cases (e.g., a line with VAT + withholding 23% RIT AG + ENASARCO), the validation fails and the user gets a blocking error in account.move.send. Since ENASARCO already has dedicated support through the AltriDatiGestionali tag on the line, we allow it to pass the check as if it were only a pension fund, restoring the previous behavior before we added the withholding flag. Some validation added and fields clear up in the tax editing phase, preventing invalid cases. Ticket [link](https://www.odoo.com/odoo/project.task/5154223) opw-5154223 Forward-Port-Of: odoo/odoo#233698 Forward-Port-Of: odoo/odoo#232140