Monday, September 28, 2026
12 changes · saas-19.4
Resolved issues and error corrections
Fixed an issue where selecting a product on a new vendor bill line could fail to save the product and instead place its name in the description. This helps ensure vendor bills reflect the user's chosen products correctly during entry.
Original PR description
Currently, new/virtual account move line records in a vendor bill does not respect the user's product selection. It places the name of the product in the description while leaving the product_id…
Currently, new/virtual account move line records in a vendor bill does not respect the user's product selection. It places the name of the product in the description while leaving the product_id false. This issue only exists in 19.4 due to the altered function [_onchange_name_predictive](https://github.com/odoo/enterprise/pull/117575) and version 20 introduced a [refactor](https://github.com/odoo/odoo/pull/273948) which separates the description and product name from the name field of account.move.line, inherently preventing the bug. To be more specific, when a virtual account.move.line has it's product changed, the product name changes which changes the value of the name field of account.move.line since the field is product name + \n + description. This triggers _onchange_name_predictive which will in turn overwrite the product id, even if no product id was predicted, as shown below: https://github.com/odoo/enterprise/blob/80de210d1db7d73bb13ff7db124b9fa7c2565e53/account_accountant/models/account_move.py#L1043-L1059 This bug does not affect real records as the context 'disable_onchange_name_predictive' is passed for real records, ultimately preventing the overwrites for certain fields as shown here: https://github.com/odoo/enterprise/blob/80de210d1db7d73bb13ff7db124b9fa7c2565e53/account_accountant/models/account_move.py#L1090-L1094 Steps to reproduce: - Install accounting and account_accountant - Create a new vendor bill - Create a new line and select a product Bugfix-6563221
Odoo now safely ignores file upload results when the form or dialog that started the upload has already been closed. This prevents confusing client error popups and avoids leaving uploaded attachments disconnected from their record.
Original PR description
Description of the issue/feature this PR addresses: A file upload through `FileInput` (and therefore every `many2many_binary` field) still calls `onUpload` after the component has been destroyed.…
Description of the issue/feature this PR addresses:
A file upload through `FileInput` (and therefore every `many2many_binary` field) still calls `onUpload` after the component has been destroyed. When the form or dialog holding the field goes away while the upload request is in flight, the response crashes the web client with two "Odoo Client Error" popups and the uploaded attachment is orphaned.
Steps to reproduce on a stock database (19.0, and 17.0 carries the same code):
1. Open an Email Template form (Settings > Technical > Email Templates), page *Options*, field *Attachments*. Any `target="new"` wizard with a `many2many_binary` field shows the same thing, e.g. the Recruitment *Refuse* wizard.
2. Pick a file that takes a moment to upload (a few MB, or a slow connection).
3. Before the file tile appears, leave the form through the breadcrumb, or close the wizard with Escape, its close button, or its action button. Nothing in the field shows that an upload is still running, so users do this routinely.
Current behavior before PR:
When the upload response arrives, two errors are raised:
```
UncaughtPromiseError > Component is destroyed
at webRead <- _loadRecords <- _applyCommands <- addAndRemove
TypeError: Cannot set properties of null (setting 'value')
at FileInput.onFileInputChange
```
Cause: `FileInput` posts the file through the `http` service, which is not protected against a destroyed component (unlike `orm`), so the response still reaches `onFileInputChange` after the component, the field and the form controller are gone. It then calls `onUpload`, which for `Many2ManyBinaryField` links the attachment through the form controller's protected ORM (hence the rejection), and it clears a file input ref that no longer exists (hence the TypeError).
We hit this in production on three different wizards over a few months. The client error logs users saved all carry the same trace, and the audit log shows the dialog's action completing a fraction of a second before the upload landed.
Desired behavior after PR is merged:
After the upload resolves, `onFileInputChange` stops when the component is destroyed: nobody is left to receive the uploaded files, and this matches how the protected services already treat a destroyed component. No error is raised, and `onUpload` is not called.
A Hoot test in `file_input.test.js` mounts a `FileInput` behind a `t-if`, starts an upload, unmounts the input while the upload is pending, resolves the upload, and asserts that `onUpload` was not called. It fails before the fix with the two errors above and passes after.
`master` already guards the ref write through its signal-style refs, but still calls `onUpload` on the destroyed component, so the first error remains there.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#287058
Forward-Port-Of: odoo/odoo#286831AI image editing now checks whether an image format is supported before sending it to the AI provider. If the format is unsupported, such as SVG, the AI receives a note instead of failing, so users get a helpful response rather than an error.
Original PR description
Prior to this commit, the ai image tools did not check the format of the provided image before sending it to the AI provider. While editing a website, selecting an image in a format unsupported by AI…
Prior to this commit, the ai image tools did not check the format of the provided image before sending it to the AI provider. While editing a website, selecting an image in a format unsupported by AI providers (such as an SVG, e.g. the 'Your Logo' image shown in the top left) and choosing to edit it with AI would open a chat window, but the request to the provider would fail once the file was sent, since AI providers only support: {'png', 'jpg', 'jpeg', 'webp', 'gif'}.
This commit adds a format check to the image tools. When the referenced image is in an unsupported format, its raw data is no longer sent to the provider; instead, a text note describing the situation (path and format) is added to the AI's context. This lets the agent handle the request appropriately instead of the call failing outright: it can ask the user to provide the image in a supported format (or a description to recreate it), or proceed normally if the request doesn't actually require reading that image (e.g. generating a new image from scratch).
How to reproduce:
- enable the Website and AI modules.
- open the website, and enter edit mode.
- double click the website logo in the top left ('Your Logo'), then click 'AI'.
- a chat window opens; ask the AI to modify the image.
Current behavior:
- An error is raised, warning of an unsupported file format ('image/svg+xml').
Expected behavior:
- No error. The AI agent recognizes it cannot read the image in its current format and responds accordingly instead of the request failing.
task: 6432373
Forward-Port-Of: odoo/enterprise#129205This fix ensures email links copied from Odoo or external tools paste as proper clickable links in the HTML editor. It prevents pasted mail links from becoming broken links or plain text, reducing editing mistakes in messages and content.
Original PR description
**Current behavior before PR:** **Issue 1:** Steps to reproduce the issue: - Create a mail link in editor. - Copy link via link popover. - Paste it anywhere in editor. - Click on it to open popover. Notice that newly created link is not a correct mail link. **Issue 2:** Steps to reproduce the issue: - Copy a mail URL from google docs or from some other website. - Paste the copied link in editor. Notice that URL is pasted as plain text instead of link. This happens because when a link is copied with HTML content, `handlePasteText` is called after `handlePasteHtml`, and it ends up being pasted as html content. **Desired behavior after PR is merged:** This PR aims to ensure that mail URLs are being pasted correctly in editor. task-6462998 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#290538 Forward-Port-Of: odoo/odoo#282954
This fix ensures Belgian payroll correctly determines when sick leave should become unpaid after the eligible paid period. It prevents incorrect results when an employee's sickness history spans multiple years, improving payroll accuracy and reducing manual corrections.
Original PR description
The legacy check for unpaid sick time off after 30 days was wrong. The relapse period used was always the one from the latest leave, and not adapted if we span multiple years. Instead, we can just look at the l10n_be_sickness_can_relapse field, which is correctly computed. Forward-Port-Of: odoo/enterprise#132389
This fixes Belgian payroll calculations so time credit and extra hours are excluded when checking paid hours. It helps ensure payslips reflect the correct worked days amount and reduces the risk of payroll inaccuracies for employees using time credit.
Original PR description
The method checking if we have enough paid hours was wrongly adapted. We should filter out extra hours and time credit entries as they are not included in the base salary and base hours per week. Forward-Port-Of: odoo/enterprise#132809 Forward-Port-Of: odoo/enterprise#132736
Belgian payroll calculations now prorate PFA variable salary in the same way as base salary. This helps ensure more accurate payroll amounts for employees whose pay period or entitlement requires proportional calculation.
Original PR description
PFA variable salary should be prorated just like the base salary. Forward-Port-Of: odoo/enterprise#132739
This fixes a crash when adding users to payroll groups from the Groups form in Australian Payroll. It also ensures both additions and removals are properly audit-logged, improving reliability and compliance tracking without changing user workflows.
Original PR description
#### Description of the issue/feature this PR addresses:
Adding a user to a group from the Groups form crashes on an Australian Payroll-API database, and removals from that form are never audit-logged.
#### Current behavior before PR:
The audit-logging mixin reads the changed users out of the raw write command with vals.get("user_ids")[0][2], which assumes a 3-element command tuple. The Groups form sends the 2-element (4, id) LINK command, so the write raises an IndexError; UNLINK commands are silently not logged for the same reason.
#### Desired behavior after PR is merged:
Group membership changes made from the Groups form are audit-logged for both additions and removals, regardless of the command used to write user_ids. The mixin reads the members before and after the write instead of interpreting the command. No field, model or method-signature change, so it is safe in stable.
opw-6397011
Forward-Port-Of: odoo/enterprise#132821
Forward-Port-Of: odoo/enterprise#125124India e-Way Bill calculations now account for global discounts applied to invoices. This helps ensure the generated e-Way Bill values match the discounted transaction totals, reducing compliance and reconciliation issues.
Original PR description
Before this commit- We didn't consider, global discount for ewaybill After this commit- We consider the global discount for ewaybill opw-6592878 task-[6596257](https://www.odoo.com/odoo/project/967/tasks/6596257) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#290217
Kenyan eTIMS reporting now excludes taxes that do not have a KRA tax code, such as levies paid to other authorities, from the reported tax-inclusive total. This helps ensure invoices sent to the tax authority reflect only KRA-relevant taxes and avoids overstating eTIMS amounts.
Original PR description
Issue: Non KRA taxes are sent in eTIMS tax total Steps to reproduce: - With l10n_ke_edi_oscu - Create a 2% Tax named CTL with no KRA Tax Code - Create an invoice - Add a line with 16% and CTL taxes - Confirm - Send to eTIMS Current behavior: - eTIMS JSON (unaccessible) is created with 'totAmt' (total_tax_included) including non-KRA Taxes Expected Behavior! - eTIMS JSON 'totAmt' doesn't incldue non-KRA Taxes Note: eTIMS is used to report to Tax Autority, however some "taxes" (e.g. Tourism levy) are paid to other authorities (e.g. Tourism Fund) and shouldn't be included in eTIMS. opw-6456478 Forward-Port-Of: odoo/enterprise#131577
Italian invoices using the Import/Export fiscal position now apply only the intended 0% export tax instead of adding an extra N7 tax. This prevents incorrect tax combinations on invoice lines and improves compliance accuracy for Italian accounting.
Original PR description
Upon Import/Export, the 0% EX N7 tax is added by default on each tax excluded line, as it incorrectly shares the same default Import/Export fiscal position with the standard 0% EX tax. This causes both to be applied simultaneously to a single invoice line. 1. Install Accounting and `l10n_it` 2. Switch to IT company 3. Go to Invoices and create a new one 4. Select the Import/Export fiscal position 5. Add a line with a new product (so it's clean of custom product taxes) 6. Both `0% EX` and `0% EX N7` taxes are applied, instead of just `0% EX` Ticket [link](https://www.odoo.com/odoo/project.task/6518926) opw-6518926 Forward-Port-Of: odoo/odoo#285586
Portal users will no longer see Documents or Knowledge cards when they have no shared content, reducing confusion on the portal home page. Website editors can also manage visibility for these content-based cards even when older database settings marked them as always shown.
Original PR description
Issue: - The Knowledge and Documents cards are visible even when the portal user has no shared content. <img width="1344" height="525" alt="image"…
Issue:
- The Knowledge and Documents cards are visible even when the portal user has no shared content.
<img width="1344" height="525" alt="image" src="https://github.com/user-attachments/assets/b3409ba1-ff1c-4967-8acb-01baa5243f69" />
- No option to hide them with editor
<table style="width: 100%;">
<tr>
<th>Before</th>
<th>After</th>
</tr>
<tr>
<td>
<img src="https://github.com/user-attachments/assets/dfdd3d2e-a91b-4b9c-ab64-fdc6535d0fd1" alt="Before" width="280"/>
</td>
<td>
<img src="https://github.com/user-attachments/assets/001f3f57-c926-4469-9ac2-767586c3ac2c" alt="After" width="280"/>
</td>
</tr>
</table>
Steps to reproduce:
1. Install website, documents, and knowledge
2. Create a portal user and make sure no documents and knowledge article are shared with him.
3. Log in as a portal user
4. The Knowledge and Documents cards are visible (Issue 1)
5. Again login as admin and go to `/my endpoint ex: http://localhost:3000/my`
6. Click on editor and then click documents card
7. documents card and knowledge are not avaialbe for visibility change (Issue 2)
Cause:
- Commit https://github.com/odoo/odoo/commit/513931a5e540f22f37e317f80fd131701cbbc8f0 introduced portal.entry records to back portal
cards. and Commit https://github.com/odoo/enterprise/commit/512c9e49d168a205b8fe2a5ff5384c6a178762e7 defined the Documents and Knowledge
entries with `is_config_card=True` inside `<odoo noupdate="1">` records.
Because these records are loaded with noupdate="1", updating the XML data in
enterprise would not update existing databases.
Now entries are marked as config cards, and config cards are always shown
by should_show_portal_card().
https://github.com/odoo/odoo/blob/181f9aa238ae99e92ada4bc4e7064ea95d2f5b84/addons/portal/views/portal_templates.xml#L261-L264
- This is correct for real configuration cards such as Addresses or Connection & Security, but not for counter cards. A card with a `placeholder_count` represents content and should only be displayed when its counter is positive.
Solution:
- Do not force-display config cards that have a `placeholder_count`.
- Also include counter cards in the portal card visibility editor, even if they are marked as config cards in existing databases.
behavior change:
- Before: any portal.entry with `is_config_card=True` was always visible.
- After: it is always visible only if it has no `placeholder_count` and `is_config_card=True` or any records in them
- Cards with `placeholder_count`, like Documents and Knowledge, are hidden until their counter is positive.
- Before: cards with `is_config_card=True` were excluded from the portal visibility options in Edit.
- After: counter cards are included in the editor visibility options even if `is_config_card=True`
opw-6223044
Forward-Port-Of: odoo/odoo#265797