Daily updates from Odoo
Friday, October 31, 2025
19 changes · saas-18.4
New functionality added to Odoo
Adds a new Turkish Nilvera e-invoicing extension to support legally required invoice scenarios such as withholding VAT, tax exemptions, export invoices, and public sector invoices. It also adds tax office information to e-invoice data, helping businesses meet Turkish compliance requirements for domestic and international sales.
Original PR description
[ADD] l10n_tr_nilvera_einvoice_extended: Adding Nilvera E-Invoice Extension [ADD] l10n_tr_nilvera_einvoice_extended: Adding Tax Offices --- ### Description of the issue/feature this PR addresses: We…
[ADD] l10n_tr_nilvera_einvoice_extended: Adding Nilvera E-Invoice Extension [ADD] l10n_tr_nilvera_einvoice_extended: Adding Tax Offices --- ### Description of the issue/feature this PR addresses: We do not support Withholding VAT (KDV Tevkifatı), Exemption Invoices, and Export Invoices (İhracat Faturaları) with our current e-invoicing solution in Türkiye. Those invoice types are legally important and required for both domestic and international sales for businesses. In addition, the inclusion of the Tax office in our current XML we send to Nilvera, both for `<cac:AccountingSupplierParty>` and `<cac:AccountingCustomerParty>`, is required by law. This PR adds an extension module for Nilvera E-Invoicing. The purpose of this module is to extend the existing E-Invoicing functionality to support additional invoice types and scenarios to be compliant with the TR legal requirements. --- ### Invoice Scenario: **Basic** Invoice Type: - Sales - Withholding - Tax Exempt - Registered for Export **Export** Invoice Type: - Tax Exempt **Public** Invoice Type: - Sales - Withholding - Tax Exempt - Registered for Export --- ### Current behavior before PR: We don't support a scenario-based system to comply with TR legal requirements. --- ### Desired behavior after PR is merged: We support a scenario-based system to comply with TR legal requirements. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#229205 Forward-Port-Of: odoo/odoo#213766
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
This fix stops Odoo from forcing a default employee structure onto an admin employee record that may not exist in some customer setups. It prevents upgrade or employee creation failures for companies that use their own HR administration workflow.
Original PR description
After this commit: https://github.com/odoo/odoo/commit/6247dc36f703ee2ec45913802ad175cb79873845 and this one: https://github.com/odoo-dev/odoo/commit/5686072b8e7b827269573e8ab1f5b84b61b9315c when we…
After this commit:
https://github.com/odoo/odoo/commit/6247dc36f703ee2ec45913802ad175cb79873845 and this one:
https://github.com/odoo-dev/odoo/commit/5686072b8e7b827269573e8ab1f5b84b61b9315c
when we set default Structure to employee admin
but Later when clients set up their work flow
they set up their own admin employee.
This record is not present, so when employee admin record is not there , no need to set default structure too so need to set no forcecreate on that employee admin too.
When we try to set default structure and if admin record does not exit,
we got error when we try to create employee as no name found and we try to pop name from val here :
https://github.com/odoo/odoo/blob/7e0cc5ec686a52b8c1f8270213acac54575ed469/addons/hr/models/hr_employee.py#L1275
Generated during upgrade
```
File "/home/odoo/src/odoo/19.0/addons/resource/models/resource_mixin.py", line 37, in create
self._prepare_resource_values(
File "/home/odoo/src/odoo/19.0/addons/hr/models/hr_employee.py", line 1275, in _prepare_resource_values
vals.pop('name') # Already considered by super call but no popped
KeyError: 'name'
```
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-prCorrects 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
This update makes an automated test for Discuss sub-channel search more stable under heavy system load. It helps ensure thread loading during search continues to be verified reliably, reducing false test failures without changing user-facing behavior.
Original PR description
The `test_discuss_sub_channel_search` tour ensures that lazy loading of threads works correctly with the search feature. Technically, the component uses the `useVisible` hook which waits for a trigger to be visible before loading more threads. However, under high CPU load, the `IntersectionObserver` might not detect the change. For example, clearing the search input will make the element disappear, but scrolling afterward may make it reappear. As a result, the component might not detect that it should load more threads. In practice, this should never happen. The test now waits for the state to update before scrolling. fixes runbot-181951 Forward-Port-Of: odoo/odoo#233419
This fix removes an outdated action in the self-ordering flow that could trigger errors after a related function had already been removed. It helps keep restaurant self-ordering sessions stable for customers and staff.
Original PR description
Before this commit, there was still a call to the resetTableIdentifier, even though the function had been removed, which could cause errors. opw-5166737 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#232521
This fixes an issue in Point of Sale where a lot number could still be applied to a sale order line even after the user canceled the lot selection. The change helps prevent incorrect product tracking information from being added during order loading.
Original PR description
Before this commit, when loading a sale order containing an order line tracked by lot, the system prompted the user to select a lot. However, even if the user canceled the selection, the lot was still added to the order line. After this commit, the lot will no longer be set if the user cancels the selection. opw-5162487 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#233281
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
The printed approval request report now has cleaner spacing and more consistent text sizing. This makes approval details easier to read and better aligned when users print or review their requests.
Original PR description
Steps to Reproduce: - Install approvals module. - Navigate to Approvals → My Approvals → My Requests → Print report. Issue: - The formatting of the report is not proper. Solution: - Fixed the report's QWeb template (approvals.report_aprroval_request_document). - changed col-2 to col-3 to give the labels more space and improve alignment with the field values - changed h5 to h6 for more consistent and appropriate font size throughout the document **before :** <img width="777" height="818" alt="image" src="https://github.com/user-attachments/assets/86cbaf50-191a-412b-9b8e-149442256819" /> **after :** <img width="829" height="623" alt="image" src="https://github.com/user-attachments/assets/da237a87-7a7b-45db-8347-d64e1e987469" /> Forward-Port-Of: odoo/enterprise#95609
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
Payroll users who are allowed to resend payslips by email can now generate the secure payslip link needed in the email. This fixes an access issue that blocked the “Your Payslip” button from being included correctly.
Original PR description
Hr Payroll users that are meant to be able to use the Resend Payslip by email button do not have enough access right to get the documents token to put into the email "Your Payslip" button. Add a sudo on the payslip to get the document access url after the check of user role has been done. If have the right to use the button, sudo the rest. Task-5049444 Forward-Port-Of: odoo/enterprise#93420
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
Creating a new salary offer from an existing offer now generates a valid link with a unique access token. This prevents employees or candidates from receiving unusable offer links ending with an invalid token value.
Original PR description
_______________________________________ ## Short functional explanation of the error When creating an offer on the page of another offer, the salary configurator url doesn't contain a token, but instead, contains token = false. ## Reproduction Steps 1. Open the recruitment module. If there's no job position nor application, create some. 2. Open an existing application and click on Generate Offer. 3. Click on New on the top left of the screen. 4. Fill the new application and click on save. ### Expected behavior The field 'Link' contains an URL with, at the end, &token=x, with x a randomly generated token. ### Unexpected behavior The field 'Link' contains an URL with, at the end, &token=False. ## Origin of the issue The token generation code wasn't called when creating a new offer the way described in reproduction steps. _________________________________________ opw-4885796 --- Forward-Port-Of: odoo/enterprise#89546
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
Shared project users no longer see an unintended slider option when opening tasks from the portal. This keeps the shared project view focused and prevents confusing controls from appearing to external users.
Original PR description
Steps to reproduce: - Open any shared project from portal account. - Open any task Issue: - Visible slider with Show Sub Tasks option. Reason: - Unwantedly added ControlPanel into FormView of Project Sharing View. - Issue from https://github.com/odoo/odoo/pull/224203. Fix: - Remove the ControlPanel in Form View and extend web Control in xml to acheive the button.
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