Wednesday, December 3, 2025
21 changes · saas-18.3
Resolved issues and error corrections
This update resolves an issue where duplicate account IDs were causing data overwrites. The changes update account codes for CPF, SHG, and SDL tax calculations, aligning with new Singapore tax regulations. The change also simplifies account code formatting to prevent excessively long codes.
Original PR description
Two accounts were using the same XML ID `account_account_864`, causing second definition to overwrite the first. This commit resolves the duplication and updates/segregates accounts for CPF and SHG according to new specifications.
Changes:
- Update `account_account_864` (Employee Expense) to `account_account_866`.
- Update in accounts:
* 862 → CPF Withheld (Employee)
* 863 → CPF Accrued (Employer)
* 864 → SHG Withheld (Employee)
* Add new 865 → SDL Accrued (Employer)
* 859 → CPF Employer Expense
* 860 → SDL Employer Expense
* Removed 861
- Fix `transfer_account_code_prefix` in the template:
* Change from `101100` to `10110` to avoid generating 7-digit account codes.
task-5360160
Forward-Port-Of: odoo/odoo#238264
Forward-Port-Of: odoo/odoo#237506A minor typo in the SEPA Direct Debit payment provider configuration has been corrected. The change ensures grammatically correct messaging is displayed to users, improving clarity and professionalism. This fix addresses a simple formatting issue.
Original PR description
Currently, a typo appears in the `Pending Message` shown in the SEPA Direct Debit payment provider configuration. **Steps to reproduce:** - Install the `payment_sepa_direct_debit` module. - Navigate…
Currently, a typo appears in the `Pending Message` shown in the SEPA Direct Debit payment provider configuration. **Steps to reproduce:** - Install the `payment_sepa_direct_debit` module. - Navigate to Invoicing > Configuration > Payment Providers > SEPA Direct Debit. - Open the `Messages` tab and observe the `Pending Message`. **Observation:** The message uses "an unique" instead of the grammatically correct "a unique". **Fix:** This commit corrects the message by replacing "an" with "a" at [1]. Before: <img width="1903" height="606" alt="typo_before" src="https://github.com/user-attachments/assets/df4f658b-9f4c-4e68-b8cb-a1bdc2253fc3" /> After: <img width="1900" height="609" alt="typo_after" src="https://github.com/user-attachments/assets/e9192d70-b343-4e4e-9e21-281a93d4d71e" /> [1]: https://github.com/odoo/enterprise/blob/6c3692d85bf1ef7b14d930d9a1ed244cf8aa851b/payment_sepa_direct_debit/data/payment_provider_data.xml#L13 opw-5373274 Forward-Port-Of: odoo/enterprise#100983
A technical error was causing a traceback when generating salary package offers. This update corrects a flaw in the system's logic that occurred when 'Always Selected' benefits were present, preventing the offer generation process from failing. This ensures smooth and reliable offer creation for employees.
Original PR description
Steps to reproduce: 1. Install 'hr_contract_salary_payroll' 2. Create three benefits from Payroll > Configuration > Benefits - Basic: Salary Structure Type: US Employee Contract Related Field: Health…
Steps to reproduce:
1. Install 'hr_contract_salary_payroll'
2. Create three benefits from Payroll > Configuration > Benefits
- Basic:
Salary Structure Type: US Employee
Contract Related Field: Health Benefits Dental
Display Type: Slider (1500, 6000)
- Housing:
Salary Structure Type: US Employee
Contract Related Field: Health Benefits Vision
Display Type: Always Selected
- Transport:
Salary Structure Type: US Employee
Contract Related Field: Health Benefits Vision
Display Type: Manual
Mandatory Benefits: Basic, Housing
3. Go to Employees > Contracts
4. Create a new contract:
Set an employee
Salary Structure Type = US Employee
HR Responsible = Mitchell Admin
5. Click the Generate Offer smart button.
6. Open the link
7. Adjust the sliders
Issue: it gives a traceback
`TypeError: Cannot read properties of undefined (reading 'type')`
Cause:
https://github.com/odoo/enterprise/blob/cc3fe89528a143cff3ab03e1654755c34eaac112/hr_contract_salary/static/src/js/hr_contract_salary.js#L480-L482
In checkInputSelected, the target array is empty when an Always Selected benefit is present, causing an attempt to read target[0].type.
Solution:
Add a guard to check that target is not empty before accessing its elements.
opw-5058994
Forward-Port-Of: odoo/enterprise#94881This update fixes an error that prevented payroll officers from accessing salary offer details. The issue stemmed from the module attempting to access candidate records, which required recruitment rights. The fix ensures payroll officers can now open and manage offers without needing these additional permissions.
Original PR description
steps to reproduce: - Install l10n_be_hr_contract_salary - Log in as a payroll officer (without recruitment rights) - Go to Payroll > Contracts > Offers - Open any offer - Notice an 'Access Error' appears: You are not allowed to access 'Candidate' (hr.candidate) records. cause: The module tries to read `employee_id.candidate_id.partner_id` in offer computations. Since payroll officers lack recruitment rights accessing `hr.candidate` triggers an access error. fix: Wrap candidate access in try/except to handle missing permissions. - If accessible, candidate partner data is used as before. - If not accessible, skip without raising an error. This allows payroll officers to open and generate salary offers without requiring recruitment rights. task - 5039712 Forward-Port-Of: odoo/enterprise#100980 Forward-Port-Of: odoo/enterprise#95869
This update fixes a visual glitch on the Odoo website where the header would unexpectedly disappear after scrolling. The issue was caused by a timeout in the animation process, now resolved to ensure a smoother and more reliable user experience. This improves the overall appearance and usability of the website.
Original PR description
Steps to reproduce the issue: - Go to Edit mode - Click on the Header - In the "Scroll Effect" dropdown, select "Fade Out" - Drop some snippets to allow scrolling on the page - Scroll down then scroll to top QUICKLY The timeout to hide the header after the fade animation end is not cleared. Therefore, after 400ms, the header is shifted upward and disappears, even if the user scrolled up and made the header reappear. task-5357217 Forward-Port-Of: odoo/odoo#237515
This update corrects a bug where discounts from purchase orders were incorrectly being added to sale orders during import. The fix ensures that sale order lines always reflect a discount of 0, aligning with expected business logic. This was triggered by a recent code change and addressed with a targeted test.
Original PR description
Discounts are always sent by `_retrieve_line_vals` in `account_edi_ubl_cii` In Sale orders, discounts aren't expected to be automatically imported from the purchase order, it should always be 0. `test_so_import_product_from_po` didn't use to fail because discount wasn't checked until the recent refactor https://github.com/odoo/odoo/pull/190310 Check was added in 18.0 to avoid this error in the future. Steps to reproduce: - Disable discount in sale app - Create a PO with a discount on any POL - Enable discounts - Import SO from PO Issue: Discount is added to the Sale order lines. Runbot: 232724 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#238203 Forward-Port-Of: odoo/odoo#237743
This update fixes a visual issue where buttons within the image field were not vertically centered. The change utilizes SCSS flexbox to ensure consistent and reliable centering, accommodating the field's custom sizing. This improves the overall appearance and usability of the image field.
Original PR description
The buttons in image_field are not centered vertically. Since it's a custom sized button, using flex is reliable (it's now centered on both flex axis). Note: Done in SCSS instead of utilities because the flex is there to compensate the custom size set in SCSS (easier to maintain) + there could be injected buttons in the component. task-5258887 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#235964
This update resolves a printer blocking issue that occurred when printing receipts with reward lines and multiple order items. The fix ensures accurate discount calculations, preventing errors that previously caused the printer to halt. This improves receipt printing reliability for Italian POS users.
Original PR description
This PR fixes the case of printer blocked using reward lines and multiple order lines. To reproduce the issue: - Add a product with reward (for example 10% reward on 50€ , that is 5€) - Add a second product without reward that costs less than 5€ - Print the receipt on fiscal printer The lines are orderer before the non reward lines, than reward lines. The printer is blocking because the adjustmentType discounts last line of less than 5€. It is wrong. Another way to reproduce the issue: - Add a product with reward - Add a second product with reward - The reward line with the sum of both rewards is created The same error appear because it discounts both lines. It is better to discount the entire department instead of the last sale Forward-Port-Of: odoo/enterprise#98699
This update fixes an issue where the table editor incorrectly selected adjacent cells when users tried to select all text within a cell using Shift and arrow keys. Now, after selecting all text, only the current cell is selected, allowing for more precise editing and selection of individual cells.
Original PR description
**Current behavior before PR:** Steps to reproduce: - In an m × n table, type some text inside a cell. - Place the cursor at the end of the text. - Hold Shift and repeatedly press ArrowLeft until the entire cell becomes selected. Once the cell content is fully selected, the cell itself is selected along with its adjacent cell, instead of only the current cell. **Desired behavior after PR:** After selecting all text, the current cell alone should become selected. Pressing Shift + ArrowLeft again should then extend the selection to the adjacent cell. task-5268801 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#235959
The POS digest email now accurately reflects all POS orders, regardless of invoicing status. Previously, the ‘Open Report’ link within the digest would only display invoiced orders, resulting in a blank page when all POS orders were uninvoiced. This fix ensures the digest provides a complete and accurate report.
Original PR description
The POS digest email shows metrics based on *uninvoiced* POS orders, but the “Open Report” link in the digest opens a report filtered to *invoiced* orders only. As a result, when all POS orders are uninvoiced, the link leads to an empty view. ### Steps to reproduce 1. Ensure that all existing POS orders are **uninvoiced**. 2. Enable Developer Mode, then navigate to **Settings → Technical → Email → Digest Email**. 3. Open any digest and click **"Send Now"** to generate a new digest email. 4. Open the generated digest and click the **POS report** link. This results in a blank page. ### Cause There is a mismatch between: * the digest computation (showing only uninvoiced orders), and * the report view called by the digest link (showing only invoiced orders). ### Fix Ensure the POS report shows unvoiced orders. opw-5087701 Forward-Port-Of: odoo/odoo#236727
This update resolves an issue where the Odoo application remained listed after uninstalling on Windows. The fix ensures the correct registry keys are removed during uninstallation, preventing persistent entries in the installed software list. This improves the user experience and maintains accurate software tracking.
Original PR description
Since d0d0fa2b8e the Windows installer only supports 64 bit version of the OS. It was recently noticed that when uninstalling the app with the provided uninstaller that the app remains listed in the installed software. Although the directories and third party apps were correctly cleaned and removed. The reason is that the Odoo app registry key is still present after the uninstall process. When a 32 bit process tries to write a registry key in `HKLM\SOFTWARE` it's redirected by the OS to `HKLM\SOFTWARE\WOW6432Node`. By using the `SetRegView 64` NSIS directive, the installer writes the registry key at the right place ... but the uninstaller is lacking that directive and thus tries to remove a non existing key in `HKLM\SOFTWARE\WOW6432Node`. With this commit, the uninstaller is fixed by using the directive too. Forward-Port-Of: odoo/odoo#238476
This update resolves an issue where 'Member' users encountered an error when using AI fields with references to Studio fields. Previously, they were incorrectly denied access, requiring 'Email template editor' permissions. Now, AI fields can correctly render templates using Studio fields, improving usability for all users.
Original PR description
Description of the issue/feature this PR addresses: 'Member' users can use the AI field button when the prompt contains standard field references. When the prompt contains a Studio field reference,…
Description of the issue/feature this PR addresses: 'Member' users can use the AI field button when the prompt contains standard field references. When the prompt contains a Studio field reference, there is an error message stating 'email template editor' access is required. Current behavior before PR: -Create an internal 'Member' user -Add a 'user' group for the app you want to test on (bug spotted in Helpdesk) - Make a plain text Studio field -Make a text AI field where the prompt references the plain text Studio field you just created. -Make a text AI field where the prompt references a standard available field. -Log into the database as the 'Member' user -Push the 'AI' button on each of the two fields you created. -The one referencing the standard field should populate as normal; the one referencing the Studio field will trigger an error message asking for 'Email template editor access'. Desired behavior after PR is merged: Allowing AI fields unrestricted access to render the template when the studio field is used to avoid access error. Task-5016767
This update resolves an issue where users couldn't access subchannels within group chats without being explicitly invited. The fix automatically adds users as members to these subchannels when they have write access to the parent group chat, improving usability and preventing access errors.
Original PR description
Before this commit, typing in a subchannel of a group DM of which you are not member of would result in an access error. Steps to reproduce: 1. Log in as user A 2. Create group chat with user B 3. Create a subchannel in said group 4. Log in as user B 5. Open the subchannel in the group chat 6. Write in the composer -> access error This is caused by incomplete access rules for the `discuss.channel.member` model. Specifically the issue stems from the fact that a subchannel of a group channel is considered a group, and as such it's only possible to join it via invitation. Since typing in a channel attempts to join it, an access error is raised. This commit fixes the issue by executing the creation of a channel member for subchannels as superuser, on the condition of having write access to the parent channel. task-5357621 Forward-Port-Of: odoo/odoo#237611
This update resolves an issue where the ChatGPT plugin toolbar button was disabled when no text selection was made in the HTML editor. Now, the button functions consistently: opening the chat window without AI buttons when no selection is present, or with AI buttons when a selection is made. This ensures a smoother user experience for all users.
Original PR description
This PR fixes an issue with the toolbar button. Before when no selection were applied in the HTML Editor, the button would be disabled. This PR introduce a fix that makes the button enabled in two scenarios: - Either the user has no selection, clicking the button will then open the chat window without any AI button, as it does with the powerbox buttons, - Or the user has a selection, then clicking the button will result in opening the chat window with the AI buttons as it was already the case. If the user has a selection that is empty, then the button remains visible but is disabled.
This update resolves a technical issue in the tests for the pos_settle_due module, specifically addressing a hardcoded year in order line names. The fix ensures accurate test results and prevents potential discrepancies in order processing. This improves the reliability of our testing procedures.
Original PR description
This commit expands on https://github.com/odoo/enterprise/pull/93166 to remove hardcoded years in the name of the orderlines in tests. The mentioned PR fixed `clickSettleOrderName` calls in the tours, but missed the `containsOrderLine` that checked for the hardcoded year in the order lines. Runbot error: https://runbot.odoo.com/odoo/error/232848
This fix resolves an issue where the website page URL input field was unstable, causing data loss when users typed slowly with a slow connection. It also addressed a related problem where the 'Redirect Old Url' feature wasn't properly hidden after reverting changes. The update ensures a smoother and more reliable user experience when editing website pages.
Original PR description
Scenario: - edit a website page (eg: /test that you create) - go to Site > Properties - have a slow connection and write in field "Page URL" for some seconds Result: the input jitter, if going too…
Scenario: - edit a website page (eg: /test that you create) - go to Site > Properties - have a slow connection and write in field "Page URL" for some seconds Result: the input jitter, if going too fast the text can be removed to get previous version. Secondary issue: if we cancel our change and set back the original URL, the "Redirect Old Url" part is not hidden. Reason: we trigger onchange at each input event, so if we write 20 letters we will possibly still have 20 onchange that are ongoing and will set back older version of the field value. The secondary issue is because we are using a field using useInputField and FieldUrl but we are hacking it to remove the "/" prefix inside the input. So when the invisible modifier is checked, we check eg. "old_url=/test" against "url=test" that are always different. With this fix: Since the triggered onchange were only to update quicker the condition `invisible="old_url == url"`, we trigger them only if that condition will change, and debounce it to prevent the now single onchange of happening in the middle of text input. And for the secondary issue, we add and remove the / when triggering the onchange. opw-4517181 Forward-Port-Of: odoo/odoo#237610 Forward-Port-Of: odoo/odoo#200016
This update resolves an issue where the 'I agree' button on the website's cookie bar stopped working when the button's font size was adjusted. The fix corrects a technical error in how the button's click event was handled, ensuring the cookie consent process continues to function correctly regardless of font size changes.
Original PR description
The "I agree" button in the cookie bar would stop working if its font size was changed. Steps to reproduce: =================== - Enable the cookie bar in website settings. - Go to the website and…
The "I agree" button in the cookie bar would stop working if its font size was changed.
Steps to reproduce:
===================
- Enable the cookie bar in website settings.
- Go to the website and enter Edit mode.
- Click on the cookie bar.
- Select the "I agree" button's text and change its font size.
- Save and visit the page as a guest (e.g., in a private window).
- Click on the "I agree" button text.
-> The maps doesn't show and the Cookie bar disappear.
Cause:
======
Applying a font size to the button's text wraps that text within a `<span>` element.
The event listener for accepting cookies is attached to the elements with IDs `#cookies-consent-essential` and `#cookies-consent-all`. in that case it ID `cookies-consent-essential` exist in the parent element. However, the code was checking the ID of `event.target`. When a user clicks directly on the newly created
`<span>`, `event.target` refers to the `<span>` itself, not the element who owns the event.
Since the `<span>` does not have the required ID ('cookies-consent-all'), the condition to accept the cookies was false.
Solution:
=========
Use `event.currentTarget` instead of `event.target`.
Unlike `event.target`, `event.currentTarget` always refers to the element to which the event handler was attached—in.
check:
https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget
opw-5004645
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#238238
Forward-Port-Of: odoo/odoo#237786A recent issue preventing tests from running correctly with faketime has been resolved. The fix addressed a hardcoded year in the tests, ensuring compatibility across different years and preventing test failures. This improves the reliability of our point-of-sale settlement testing process.
Original PR description
When running the pos_settle_due tests with faketime, the tour pos_settle_account_due was failing cause of a hardcoded year which would not work on another year. This is now fixed. runbot-error: 234052
A bug in the payment state test has been fixed. The test now correctly reflects the payment state of invoices based on whether the ‘accountant’ module is installed. This ensures consistent invoice tracking across different Odoo Enterprise configurations.
Original PR description
The `test_bill_state_change_on_payment_state` is throwing an exception. ``` self.assertEqual(payment.invoice_ids.payment_state, 'not_paid') AssertionError: 'paid' != 'not_paid' - paid + not_paid ```…
The `test_bill_state_change_on_payment_state` is throwing an exception. ``` self.assertEqual(payment.invoice_ids.payment_state, 'not_paid') AssertionError: 'paid' != 'not_paid' - paid + not_paid ``` The test was incorrectly expecting invoice `payment_state` to always be `not_paid` when payment is reset to draft, but behavior differs based on whether `accountant` module is installed or not. - With `accountant`: Payment has no move_id (no journal entry created by default), so when drafted, `invoice.matched_payment_ids` filters exclude it, resulting in 'not_paid' state. - Without `accountant`: Payment has move_id (journal entry auto-created) so filter conditions fail (`not p.move_id` is `False`), and invoice stays `paid` due to existing reconciliations in `draft` state. Test was introduced here: https://github.com/odoo/enterprise/pull/100834/commits/402bd85af79fa68fa2cb957d40307edf62f7525c Commits that introduced the behavior change: https://github.com/odoo/odoo/pull/182390/commits/b572fcd78289013f28f11157b1bfbb75c9ea7344 https://github.com/odoo/odoo/blob/57f1053b031f293c6cd8dc8f590dccda4fb3e665/addons/account/models/account_move.py#L1308-L1314 Runbot [link](https://runbot.odoo.com/odoo/error/234573) runbot error: 234573 Forward-Port-Of: odoo/enterprise#101089
This update corrects a technical issue where default Incoterms were incorrectly applied to bills. Bills represent invoices from third-party vendors, and using our default Incoterms would have created inaccuracies. This change ensures bills accurately reflect the terms of the vendor's invoice.
Original PR description
Incoterms are usefull to indicates the rules and terms in sale contracts. It makes sense to add the company default on invoices, but not on bills, as those originate from another vendor than us, who can use different rules. opw-5169146 Forward-Port-Of: odoo/odoo#236709
This update allows Odoo to utilize a new, broader range of testing VAT codes provided by our EDI partner. Previously, we only supported specific VATs, but due to the increased popularity of our EDI integration, the provider now offers a more comprehensive set of testing values. This ensures accurate VAT processing when using the EDI connection.
Original PR description
When we merged EDI for Guatemala we allowed two specific testing VATs [1]. Because our EDI is proving popular our EDI provider has now created a specific range of testing VATs just for Odoo. We allow them explicitly because they're not valid VATs. [1] 6ef9c1085cd648ad2bbd78caf4a83fe30c969d59 opw-5381791 Forward-Port-Of: odoo/odoo#238459