Monday, April 20, 2026
23 changes · master
Resolved issues and error corrections
The HTML editor now avoids opening the emoji suggestion list when a user simply types a space. This prevents distracting, unwanted suggestions while writing and keeps emoji shortcuts working as expected.
Original PR description
### Purpose of this PR: - Keywords contained spaces (e.g. "grinning face") which caused the suggestion list to open when the user typed a space. Replacing spaces with underscores in keywords fixes this since a space will no longer match any keyword. Shortcodes never contain spaces so they are unaffected. Names are removed from the lookup as they are already covered by shortcodes or keywords. task-6123666 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#259390
Taiwan ECpay invoice data now includes the product unit of measure in the item remarks sent to ECpay. This makes returned PDFs clearer for customers by showing details such as “商品單位: Units” alongside each line item.
Original PR description
Issue: -- The documents returned by the ECpay API can be confusing as it does not include the measurement (UOM). The make it clearer a description is provided to ECpay through the json with the Key "ItemRemark" Current behavior: -- displayed data in PDF 品名 數量 單價 金額 備註 test 1 5 5 Expected behavior: -- displayed data in PDF 品名 數量 單價 金額 備註 test 1 5 5 商品單位: Units opw-6070269 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#259536
Form field labels now better cover the input border behind them, preventing borders from showing through or distracting from the label. This is a small visual polish that improves readability and consistency in the web interface.
Original PR description
This commit adapts the label background to ensure the box border is always hidden under the label. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fix improves how tracked changes are displayed in mail messages, including clearer arrow formatting and company information for company-specific fields. It helps users better understand what changed and which company context applies when reviewing activity history.
Original PR description
- use the unicode for `->' - show company on company dependent
Employee and related record images will now be cached when users move between views, reducing unnecessary reloads and improving browsing smoothness. If a related image changes during the same session, users may need to refresh the page to see the latest version.
Original PR description
Steps to reproduce ================== - Login as Demo - Go to Employees - Open a record - Go back to the kanban view -> Every image is retrieved again Cause of the issue ================== When loading an image, we add a unique parameter with the write_date of the record. We cannot use that for images on another record. Since we have no way of knowing when the image was changed, we used the timestamp when instanciating the ImageField. The downside is that every time we navigate to a view, every image is reloaded Solution ======== When the image is on another model, we don't pass the unique parameter. This means the image will be cached. A page refresh will be needed if the image has been updated in the current browsing session. opw-6070176 Forward-Port-Of: odoo/odoo#258943
Odoo Mail no longer triggers duplicate emoji suggestions when users type a colon in the HTML composer, because that is already handled by the emoji tool. This keeps emoji suggestions working where needed while avoiding redundant prompts and a cleaner messaging experience.
Original PR description
Currently the emoji suggestions are triggered by the ":" delimiter, but this is already handled by the emoji plugin since https://github.com/odoo/odoo/pull/243077 This commit removes the redundant ":" delimiter from the suggestion service, and only keeps it for the composer when HTML is not enabled (since the emoji plugin only works in HTML mode). task-6127107 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#259554
The purchase order form now shows the “Ask confirmation” option inside the Expected Arrival area, with the related timing displayed on the same line. This fixes a layout issue so buyers can read and adjust confirmation settings more clearly.
Original PR description
- Go to Purchase - Open a purchase => "Ask confirmation" should inside the "Expected Arrival" field and the x day before should be on the same line of the ask confirmation task-6128288 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Portal users can now change quantities on optional sale items without unintentionally resetting their discounts. This preserves agreed pricing while still allowing normal quantity-based pricing rules elsewhere.
Original PR description
Issue: --- Discount compute depends on `product_uom_qty`. On optional lines, this recompute will reset the discount on lines, when portal user updates the quanity. Cause: --- `discount` needs to depend on `product_uom_qty` because discount needs to be computed based on the quantity due to pricelist rules. Fix: --- We can prevent this compute if the quantity update comes from portal. opw-6078083 Forward-Port-Of: odoo/odoo#259696
This fixes an internal cleanup issue that could leave outdated information behind after uninstalling a module. By clearing the affected registry caches, Odoo can avoid incorrect follow-up behavior in automated data updates and relationship tracking after uninstall operations.
Original PR description
When uninstalling a module, the ORM may replace field objects in the registry via a prefetch patch to avoid fetching deleted fields. The previous code only called lazy_property.reset_all(), which resets lazy-property caches, but left _field_trigger_trees and _is_modifying_relations intact. Those structures still held references to the old field objects, and could be consulted by subsequent ORM operations, leading to incorrect trigger resolution or relation tracking. Clear both caches whenever a shared field has been patched so all registry state stays consistent with the new field objects. runbot-242251 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 Forward-Port-Of: odoo/odoo#259941 Forward-Port-Of: odoo/odoo#259820
A typo was corrected in an internal SQL constraint warning message. This helps developers and administrators see clearer guidance when configuration issues occur, with no expected impact on everyday users.
Original PR description
In this commit: --------------- - Corrected a typo in the SQL constraint warning message, updated `model.Constraint` to `models.constraint`. Forward-Port-Of: odoo/odoo#259980 Forward-Port-Of: odoo/odoo#259867
This fixes a missed internal rename in the website shop editor that could affect how editable buttons are processed. The change helps keep website customization tools working reliably after a previous update.
Original PR description
Description of the issue/feature this PR addresses: Commit [1] changed normalize_handlers into processors but an occurrence of normalize_handler was missed to updated. Most probably missed during forward port. [1]: https://github.com/odoo/odoo/commit/37c898a81dabd91914367f7172fc091da625e803 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The product catalog now handles sample product entries correctly when no vendor products are available, such as in a new purchase quotation without demo data. This prevents error messages from appearing and lets users browse the catalog smoothly.
Original PR description
Issue ===== When sample records are shown in product's catalog, the user encounters some tracebacks. How to reproduce ================ 1. Install Purchase without demo data; 2. Create a new quotation (which requires at least one vendor); 3. Click on "Catalog" => The catalog is opened but multiple tracebacks happen. Explanation =========== When there are no products to show by default (the catalog's products are filtered to show vendor's products in Purchase Order), samples are shown instead. The issue is: in `_getSampleOrderLineInfo` which generate props for sample records, there is no `uomId` prop, but `ProductCatalogOrderLine` expects one. Fix === The `uomId` prop is now optional, as it doesn't make sense to have one for sample data.
This fixes how required form fields are visually highlighted on small screens. Users will now see consistent field borders, with clearer colors that distinguish read-only, required, and invalid fields.
Original PR description
This commit fixes the input border color for required fields on small screens. The border width is now consistent, while the border color differs depending on whether the field is readonly, required, or invalid. 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
Automated test retries now start from a clean state each time, preventing leftover data from one attempt causing confusing failures in the next. This improves the reliability of Odoo's internal test process and helps teams trust test results during development.
Original PR description
The autoretry don't recreate the test instance meaning that some pollution can remain there breaking the next test with a strange error. This pr recreates the test instance for each retry to avoid this kind of issue, and move the retry mechanism to the suite level. The core part of the fix is `test = test.__class__(test._testMethodName) # re-create the test to reset its state` While on it, moving the retry mechanism in the test suite since it makes more sense and allow a better control on what is retried or not since we don't rely on inheritance, and avoid dirty code with super(test) call to recreate the instance and execute it again. The tests needs to be adapted since the retry attribute is now in the loop, but we can have a quite reliable way to know if we are in a retry or not using inspect. Forward-Port-Of: odoo/odoo#259891 Forward-Port-Of: odoo/odoo#258833
This fix prevents errors that could occur when registering payments after internal cache updates, especially in withholding tax flows. It improves reliability of payment-related operations without changing the user workflow.
Original PR description
The issue originates from `_get_batches` in `account_payment_register`, where a prefetch collection is built using `OrderedSet`. After an ORM cache invalidation, accessing fields on the resulting records could raise an error because `with_prefetch()` expects the iterable of IDs to be reversible, which `OrderedSet` does not support. This commit implements `__reversed__` on it, making it compatible with `with_prefetch()` while preserving its intended behavior. A unit test is also added in `l10n_account_withholding_tax` to cover the prefetch traversal scenario. task-[6108453](https://www.odoo.com/odoo/project/967/tasks/6108453) Forward-Port-Of: odoo/odoo#259805
The Dutch ICP report now rounds amounts down to whole numbers, matching the rounding already used in exports. This reduces confusion and helps businesses compare report and export values consistently for Dutch tax reporting.
Original PR description
Description of the issue this commit addresses: The Dutch tax authority lets ICP amounts be rounded down which is the behavior of the exports but not of the report itself meaning the values to not match and is quite confusing. --- Desired habevior after this commit is merged: The integer rounding DOWN is added on the ICP report to restore matching values --- task-6065382 Forward-Port-Of: odoo/enterprise#114277 Forward-Port-Of: odoo/enterprise#112953
A payroll employee field in Belgian localization was being checked too early, before the needed payslip data existed. This change prevents that premature check so holiday pay recovery values are calculated at the right time, improving reliability of payroll tests and results.
Original PR description
…ield The computed, non-stored field `l10n_be_holiday_pay_recovered_n1` had tracking enabled. When writing to any field on the employee, the `write` method calls `_track_prepare` for tracked fields if `mail_notrack` is not set in the context. `_track_prepare` reads the current value of tracked fields to store initial values. Because `l10n_be_holiday_pay_recovered_n1` is non-stored with no dependencies, this triggered a computation at the very beginning of the test, before payslips existed. Later, when payslips were created, the field was never recomputed, causing incorrect values and test failures. Previously, the `tracking_disable` context prevented early computation. The fix removes the tracking attribute entirely, so the field is only computed when accessed, avoiding premature reads and fixing the tests. task: 6095445 Forward-Port-Of: odoo/enterprise#114063 Forward-Port-Of: odoo/enterprise#113015
This update fixes an error that could block upgrades of the Accounting Reports module. It ensures required report grouping data is correctly set, helping upgrades complete smoothly without manual intervention.
Original PR description
Bug introduced by odoo/enterprise#113124, when trying to upgrade the module `account_reports`, traceback error: > psycopg2.errors.NotNullViolation: null value in column "horizontal_group_id" > of relation "account_report_horizontal_group_rule" violates not-null constraint.
The Time Off overview no longer crashes when a new company or localization has no time off records yet. This ensures users can open the dashboard normally even before any time off data has been created.
Original PR description
Steps to reproduce: 1. Create a new company or install a localization (resulting in 0 time off records). 2. Open the Time Off overview (defaults to the Dashboard Gantt view). -> OwlError: Cannot…
Steps to reproduce: 1. Create a new company or install a localization (resulting in 0 time off records). 2. Open the Time Off overview (defaults to the Dashboard Gantt view). -> OwlError: Cannot destructure property 'type' of 'fields[fieldName]' as it is undefined. Cause: Following the recent work entries refactoring, the JS function `_fetchUserFavoritesWorkEntries` was added to the base `HrHolidaysGanttModel` to fetch data from the `hr.leave` model. When the Dashboard (`hr.leave.report.calendar`) has 0 records, the frontend `SampleServer` is activated to generate fake background data. It builds its schema based on the Dashboard view. When the JS unconditionally fires the cross-model RPC call to `hr.leave` (grouping by `work_entry_type_id`), the `SampleServer` intercepts it. Because it doesn't have `work_entry_type_id` in its Dashboard schema, it fails to evaluate the field type and crashes the Owl lifecycle. Solution: Restrict the `_fetchUserFavoritesWorkEntries` call in `_fetchData` so it only runs when not using sample data (`!this.useSampleModel`). This prevents the `SampleServer` from intercepting unsupported cross-model queries to `hr.leave` when loading empty views on fresh databases. task-5969290 Forward-Port-Of: odoo/enterprise#108618
The rental duration test has been adjusted to avoid occasional failures caused by timezone differences around midnight. This helps keep automated validation stable without changing the customer-facing rental experience.
Original PR description
The rental test intermittently fails on Runbot due to timezone offsets. Near midnight, the start time can appear after the end time, causing the datepicker to auto-shift the end date by 24h. This commit uses `getFutureDate` to set full future datetimes, bypassing browser timezone and midnight crossover issues. Runbot Error: https://runbot.odoo.com/odoo/runbot.build.error/242000
Odoo now handles LinkedIn organization image data more safely when connecting an account. If LinkedIn omits an optional image link, the setup process skips that image instead of failing, helping users complete the connection reliably.
Original PR description
When importing a LinkedIn account, Odoo fetches the image metadata of the organization page and expects each returned image to contain `downloadUrl`. For some LinkedIn accounts this key is missing from the image response, which makes the callback crash with `KeyError: 'downloadUrl'` and prevents the account from being connected. LinkedIn's current Images API documentation describes `downloadUrl` as an optional field, so the import flow should not assume it is always present. This patch skips image entries without `downloadUrl` instead of crashing. opw-6099244 Forward-Port-Of: odoo/enterprise#113812
Australian payroll no longer crashes when an employee contract has a wage but no schedule pay selected. This keeps employee payroll records usable even when pay schedule information is temporarily missing or removed.
Original PR description
This error occurs when the schedule pay is removed from an employee contract with a defined wage. Steps to reproduce: - Install `l10n_au_hr_payroll` module with demo data - Switch to `My Australian…
This error occurs when the schedule pay is removed from an employee contract with a defined wage.
Steps to reproduce:
- Install `l10n_au_hr_payroll` module with demo data
- Switch to `My Australian Company`
- Open any Employee > Payroll > `Wage` remove `schedule pay`
Traceback:
```py
File "/home/odoo/src/enterprise/saas-19.2/l10n_au_hr_payroll/models/hr_version.py", line 549, in _compute_wage
version.wage = Payslip._l10n_au_convert_amount(daily_wage, "daily", version.schedule_pay)
File "/home/odoo/src/enterprise/saas-19.2/l10n_au_hr_payroll/models/hr_payslip.py", line 511, in _l10n_au_convert_amount
coefficient = PERIODS_PER_YEAR[period_from] / PERIODS_PER_YEAR[period_to]
KeyError: False
```
We are encountering this error because the `schedule pay` is removed, causing the field to become `False`. This False value is then passed to the `_l10n_au_convert_amount` [method], resulting in a `KeyError`.
[method]: https://github.com/odoo/enterprise/blob/92c584cc1426ac70f6f77aa8216c17004fa42d35/l10n_au_hr_payroll/models/hr_payslip.py#L500-L509
sentry-7401189447
Forward-Port-Of: odoo/enterprise#113623Users can now clear the scope on an ESG emission source without triggering an error. The change keeps related activity flow fields safely empty when no scope is selected, improving reliability while editing ESG records.
Original PR description
Currently, an error occurs when the user removes the scope of the emission source. **Steps to Reproduce:** - Install the `esg` module. - Create an `emission source` record or open an `existing one`.…
Currently, an error occurs when the user removes the scope of the emission source. **Steps to Reproduce:** - Install the `esg` module. - Create an `emission source` record or open an `existing one`. - Remove the `scope` value and click anywhere. `ValueError: Compute method failed to assign esg.emission.source(<NewId origin=1>,).activity_flow_direct_indirect` **Cause:** Error started occurring in 19.0 due to a change in selection field behavior. Since from [commit](https://github.com/odoo/odoo/pull/214422/commits/8d2a42ac419fdf7943a0c11beb8c5de6c6f85bef), selection fields no longer display an “empty” value. To remove a value from a selection field, the user must clear the field, similar to a many2one field. when the user removes the scope value, The system attempts to compute the activity flow, but since the scope is False, it does not match any case [1]. As a result, the method fails to assign a value to activity_flow_direct_indirect, raising an error. This commit ensures that the activity flow and activity flow direct indirect are initialized to False. If no condition matches, the field remains False, preventing the assignment failure. [1]: https://github.com/odoo/enterprise/blob/eaf4b7559b8eb6c538820d6e54f583a41077ac3d/esg/models/esg_emission_source.py#L79-L89 Forward-Port-Of: odoo/enterprise#114079