Monday, September 28, 2026
65 changes · master
New functionality added to Odoo
Odoo now includes payroll localization for Uzbekistan, covering local salary rules, leave payouts, severance handling, and payroll-to-accounting integration. This helps businesses in Uzbekistan calculate payroll more accurately and align payroll processing with local requirements.
Original PR description
Add the Uzbekistan payroll localization: - Salary Rules: income tax, social tax, severance, remaining leaves payout, pension contribution - Uzbekistan specific work entry types: study leave, annual labor leave - Uzbekistan specific departure reasons and whether the employee is entitled to severance - Computation of average salary and payout of annual labor leaves - Demo data - Payroll account module to bridge the payroll and accounting modules for UZB task-6332256 Original PR on master: odoo/enterprise#126843 Forward-Port-Of: odoo/enterprise#132123
Odoo now includes payroll localization support for Uzbekistan, adding country-specific payroll accounts and work entry types. This helps businesses in Uzbekistan manage salary, pension, severance, and social tax processes more accurately within Odoo.
Original PR description
Added the Uzbekistan payroll localization. Added new work entry types to the hr_holidays and hr_work_entry_type_data. Added UZ salary, pension, severance, social tax accounts. task-6332256 Original PR on master: odoo/odoo#283251 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#289139
Enhancements to existing features
The media dialog now presents icons in clearer themed groups, making it easier for users to browse related options. Icon search is also more reliable across languages, accents, and multi-word searches, while new checks help prevent missing or broken icons in future updates.
Original PR description
[IMP] web, website: add tests for the icon list --- __Before commit__ `icons.py` is generated by `web/tooling/icons/generate_icons.py`, but no tests checked whether it contained all icons from…
Resolved issues and error corrections
When HR users select a private city for an employee address, the related state and ZIP code now appear immediately instead of only after saving. This keeps address entry consistent and reduces confusion during employee record updates.
Original PR description
Picking a city didn't fill in state and zip until you saved. Added an onchange so it happens live, same as we already do for state/country. Task 6482304
Features or functions removed from Odoo
Odoo removed old website styling rules that were no longer used and could cause display issues on mobile pages. This helps prevent elements such as maps from being hidden on smaller screens, with minimal expected risk.
Original PR description
The lines removed in this commit were marked as "Probably outdated" 8 years ago ([in 2018]). The table classes (`.table_desc` and `.table_heading`) are not used anywhere, and the generic rule on mobile does not seem needed anymore (in fact it generates design bugs, which is why we found these outdated rules because the map on `s_hours_and_place` snippet was hidden on mobile since [1]). The risk is low enough that we can delete those rules now. [in 2018]: https://github.com/odoo/odoo/commit/4dce6cc98b2b95a00249ac29245305e08f288e6c [1]: https://github.com/odoo/odoo/commit/7ff08d3d8fa9527b3e3d662d4f2a51feec5a1790
Code cleanup and technical improvements
This update renames an internal mail interface component to better reflect its purpose as a popover rather than a dropdown. It does not change business functionality, but it helps keep the code clearer and easier to maintain for future mail and discuss improvements.
[IMP] web, website: add tests for the icon list
---
__Before commit__
`icons.py` is generated by `web/tooling/icons/generate_icons.py`, but
no tests checked whether it contained all icons from
`icons_wishlist.txt` and `odoo_ui_icons_config.json`. This could lead
to missing icons if someone forgets to regenerate the fonts.
__What's added__
- A Python test asserting that `ICONS` in `web/icons.py` matches
`icons_wishlist.txt` and `odoo_ui_icons_config.json`.
- A step in the website `media_dialog` tour that verifies each icon
offered by the media dialog renders properly by measuring its width,
ensuring there were no errors during generation.
[IMP] web: order the icon picker's icons by theme
---
The media dialog lists the icons in the order `web/icons.py` declares
them, and that order was alphabetical: `arrow_back` sat between
`article` and `arrow_circle_down`, `crop_landscape` far from `crop`, the
`cc_*` cards scattered through the brand icons. Browsing the dialog
meant scrolling past unrelated icons to reach a variant of the one
already on screen, which only search made bearable.
Both sources are now ordered by theme -- arrows, layout, text, media,
payments, brands ... -- with the variants of an icon kept side by side,
and the generator hands that order over to `icons.py` as it is instead
of sorting it away. `icons_wishlist.txt` carries `#` headers naming
each group, so a new icon has an obvious place to be added to.
The fonts are unchanged: they are still built from a sorted wishlist and
laid out by codepoint, which is what keeps two builds of the same icon
set byte-identical.
[IMP] web, html_editor: translate the icon search tags
---
Every icon of the media dialog carries a long list of search tags
(`wheelchair`, `basket`, `magnifying glass` …) that never reaches the
browser: the needle is matched against them server-side. Those tags
were English only, so a user searching in their own language found
nothing unless the word happened to be part of the icon name.
The tags are now declared with `_lt` in `web/icons.py`, and
`search_icons()` takes an optional `translate` -- `env._` from the
controller -- to match them in the user's language. They stay lazy
because the dict is built at import, long before any language is known.
The English tags remain searchable whatever the language: the index
built at import is matched first, and only the icons it misses are
translated, so an untranslated database and an English needle cost
nothing.
[IMP] web: match every word of an icon search
---
Searching the media dialog for `shopping cart` looked up that whole
string in the tags, and matched only the icons spelling the two words
in that very order. Anything a user types as two hints -- `arrow left`,
`chart bar` -- was therefore likely to return nothing at all.
The needle is now split on spaces and an icon matches when all of its
words are found, in any order, in the icon name or its tags. A word may
come from either language: only the words the English tags miss are
looked up in the translated ones.
[IMP] web: normalize the icon search needle and tags
---
Searching the media dialog for `Cafe` or `café` found nothing: the
needle and the haystack were only lowercased, so case was handled but
diacritics were not. Translated tags make this worse, since most
languages other than English spell their words with accents -- a French
user typing `marche` missed every icon tagged `marché`.
Both sides now go through `remove_accents(text.casefold())`, applied to
the needle, to the index built at import and to the tags translated on
the fly. `casefold()` also folds the cases `lower()` leaves alone, such
as the German `ß`.
The index is built from `tags._source` rather than from an explicit
`_translate('en_US')`: same string, without pretending a language is
known at import time.AI provider settings can now be turned on or off independently from the saved API key. This makes it easier to temporarily disable a provider while keeping credentials in place, and users will see clearer messages when keys are missing or invalid.
Original PR description
Prior to this PR, user had to delete the API key set in order to disable the corresponding provider option in the AI config view. With this PR, we removed the compute method to allow the enable/disable provider option independently from the API key value. Additionally, reworded error messages when API keys are unable and added custom messages when provided API key is invalid. task: 6331248
This update improves Odoo's internal upgrade tooling so more service-related code is migrated correctly during the Owl 3 transition. It helps reduce manual cleanup and lowers the risk of migration issues for future upgrades.
Original PR description
The owl3-migration is missing some of the service's mapping used to migrate the useService call site into usePlugin. This commits aims at fixing this and fixing the typos.
Payroll users will now see a chatter message whenever the estimated end date of a payslip adjustment is changed. This improves traceability by making important adjustment updates visible in the record history.
Original PR description
Add message in chatter whenever the estimated end date of a payslip adjustment is changed. Task-6588118
Indonesian payroll now includes a non-taxable Meal Allowance (Catering) salary rule. This helps employers record catering benefits correctly as benefits in kind while keeping payroll calculations aligned with local requirements.
Original PR description
Add a new salary rule for a non-taxable Meal Allowance (Catering) benefit, categorized as Benefit in Kind. task-6461730
The Belgian payroll module no longer shows a warning about missing ONSS identification because that warning is no longer relevant. This reduces unnecessary alerts for payroll users and helps them focus on items that still require action.
Original PR description
- Missing ONSS Identificantion warning does not make sense anymore task-6569900
This update makes it easier for developers to build domain filters by allowing model records to be used directly in equality checks instead of manually extracting their IDs. It reduces small implementation friction while keeping validation in place to prevent mismatched model usage.
Original PR description
--- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Salespeople are now notified as soon as a customer schedules their subscription to close at the end of the billing period. This gives teams an earlier opportunity to contact the customer and potentially prevent churn.
Original PR description
Before this PR: When a customer closes their subscription at the end of the billing period, only `end_date` changes `subscription_state` stays `in progress` until the period ends. Since tracking only assigned the "State Change" subtype on `subscription_state` changes, this update was logged silently in the chatter with no notification. The salesperson had no way to know the customer intended to leave, and no chance to retain them. After this PR: `_track_log_get_default_subtype` also returns `mail.mt_comment` when `end_date` changes and `is_closing` becomes `True`. The salesperson, already an auto-subscribed follower of that subtype, is now notified as soon as a closing end date is set, giving them a chance to act before the subscription churns. Impact: Salespersons are alerted the moment a customer schedules closure, instead of finding out after the fact, giving them a real window to reach out and reduce silent churn. Taskid-6366414
The accounting settings text for firms has been reworded to make it clearer for users. This is a small wording improvement that helps businesses better understand the relevant setting without changing functionality.
Original PR description
changing the wording for the account firm settings text. task-6578290
The Belgian payroll setup now combines two spouse fiscal status choices that had the same tax effect into one clearer option. This reduces confusion for HR users while keeping withholding tax calculations unchanged.
Original PR description
The "High Income" and "High Pension" options of the Spouse Fiscal Status field have the exact same impact on an employee's withholding taxes. Keeping them separate creates unnecessary clutter in the interface. This change merges both options into a single "With High Income or Pension" option. task-6570466
Sales orders linked to projects now show the milestone option when selling services that are invoiced based on milestones. This makes it easier for users to create and manage milestones directly from the sales order, supporting smoother project billing workflows.
Original PR description
When a product is configured as follows: ------------------ Product Type: Service Service Tracking: Create on Order - Nothing Invoicing Policy: Based on milestones user creates a sale order linked to a project,the milestone stat button will be visible on the sale order. From there, the user can also create new milestones. task-4648575
The public holiday loading wizard now warns users when holidays for the selected year already exist and will be excluded from the list being imported. This helps HR users understand why some holidays are not shown and prevents confusion or duplicate entries.
Original PR description
Notify users, while loading the public holiday from wizard, when some holidays are already present in the system for the given year and will be removed from the shown list. Task: 6559614 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Click & Collect choices made on the product page are now saved without creating an empty order first. This keeps sales data cleaner and applies the customer's delivery choice only when they actually create a cart.
Original PR description
Selecting a pickup store or the standard delivery method on the product page created an empty sale order just to store the choice, even before the customer added anything to the cart. Keep the selection in the session instead of creating a cart when none exists yet. The choice is applied to the order once a cart is actually created. task-6538541 Forward-Port-Of: odoo/odoo#288321
Support teams can now review report snapshots directly from the advanced report configuration view available in debug mode. This helps them investigate customer issues faster by checking whether reported accounting report problems are linked to saved snapshots.
Original PR description
The form view of account.report is only accessible in debug mode, so we can put more advanced debugging/configuration things in it. This way, it'll be easier for support to investigate and check whether the bug reported in a ticket is connected to the snapshots. Forward-Port-Of: odoo/enterprise#132744
The Belgian payroll process no longer shows a toast notification when ONSS rates are imported by the scheduled background job. This reduces unnecessary alerts for users while keeping the import process running as expected.
Original PR description
task-6586967 Forward-Port-Of: odoo/enterprise#132339
Spanish companies can now use one unified accounting setup instead of choosing between separate SME and Complete plans during installation. This makes it possible to change the accounting chart type later from settings, reducing setup friction and avoiding reinstallation when business needs change.
Original PR description
…ingle dynamic fiscal package The Spanish localization previously had separate fiscal packages for SMEs and Complete plans (es_pymes, es_full), forcing users to choose at installation time with no…
…ingle dynamic fiscal package The Spanish localization previously had separate fiscal packages for SMEs and Complete plans (es_pymes, es_full), forcing users to choose at installation time with no way to switch afterwards. This introduces a new unified es_general template that replaces both, along with a spanish_general_chart_type field on res.company (SMEs, Complete, Abbreviated). When the company setting changes, accounts exclusive to the deselected plan are archived and those of the new plan are activated, allowing companies to switch chart type at any time without reinstalling the localization. - Remove template_es_full.py and template_es_pymes.py - Add template_es_general.py with dynamic account loading based on chart type - Add spanish_general_chart_type field to res.company and res.config.settings - Expose the new field in the accounting configuration view as a radio widget task-6065347 I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The messaging panel has been reorganized behind the scenes to make it easier to maintain and extend across Odoo apps. This should help keep chatter-related features more consistent in areas such as leave requests, projects, portals, ratings, and eLearning without introducing major visible changes for users.
Original PR description
Replace the elements stored inside `env.inChatter` by a dedicated plugin. This also convert the proxy to signals PR enterprise: https://github.com/odoo/enterprise/pull/126791
This update adapts WhatsApp and related document, recruitment, and knowledge features to a newer shared chatter framework. It helps keep message and collaboration tools consistent across apps, reducing maintenance risk while preserving existing user workflows.
Original PR description
PR community: https://github.com/odoo/odoo/pull/280602
Messaging and live chat internals were updated to use a more consistent way of understanding where each interface element appears. This should make future improvements easier and reduce the risk of inconsistent behavior, with little direct change for end users.
Original PR description
PR enterprise: https://github.com/odoo/enterprise/pull/126501
This update adapts the Knowledge app's comment handling to recent navigation improvements in the related community code. It helps keep comments working consistently as users browse and manage Knowledge articles.
Original PR description
PR community: https://github.com/odoo/odoo/pull/280035
Followers and recipients are now shown in alphabetical order, making lists easier to scan and use. Loading more entries now retrieves smaller batches of 20 at a time, which can make these requests lighter and more responsive.
Original PR description
Before this PR: Followers and recipients were not sorted. Each request loaded up to 100 followers or recipients. After this PR: Followers and recipients are sorted alphabetically. Additionally, we now load only 20 followers or recipients at a time when making a request to load more. task-id:3293718
The Belgian payroll localization now installs the guaranteed wage interrupted day illness work entry with the correct absence request settings. This helps payroll teams apply the right configuration from the start and reduces manual corrections after installation.
Original PR description
When installing the localization for Belgium payroll, out of all of the 'hr.work.entry.type' pre-installed for the country, there was a wrong config initialization for the 'Guaranted wage interrupted day illness' one. On the XML data, the proper modifications to the 'time_off_selectable', 'requires_allocation' and 'request_unit' were updated to resemble the right case. task-6580292
This fix improves how employee work contact information is calculated so the right access rules are respected. It helps prevent unexpected behavior when HR records are updated or viewed by different users.
Original PR description
Ensure correct access to avoid unexpected behavior opw-6560194 Forward-Port-Of: odoo/odoo#289768 Forward-Port-Of: odoo/odoo#288063
This update removes an unusual default value from an internal test method parameter to align with coding best practices. It helps prevent confusing behavior in developer tooling and keeps the codebase more reliable, with no expected impact on regular users.
Original PR description
[RUF077](https://docs.astral.sh/ruff/rules/method-receiver-default/#method-receiver-default-ruf077) specifies that method receiver parameters, such as `self` and `cls`, should not have default values. The reasoning is because these parameters are usually bound by the method binding protocol, so a default value on a receiver parameter is almost certainly a mistake and can lead to confusing behavior or runtime errors. This method seems to not reference self, and this should not cause errors, but it is best practice to not do this. runbot-[947144](https://runbot.odoo.com/odoo/error/947144) Forward-Port-Of: odoo/odoo#290616
This update removes unnecessary logic in the accounting reports download flow. The change makes the code clearer and reduces the chance of confusion in future maintenance, with no expected change for users.
Original PR description
`!something` is never nullish, so `?? true` is dead code. Probably the intention was `if (!(data.no_closing_after_download ?? true))`, but reviewer has the final say and I can change it. Forward-Port-Of: odoo/enterprise#131774
The mobile navigation menu now shows a pointer cursor when users hover over menu items with a mouse or trackpad. This makes the interface feel consistent and clearly indicates that the items can be clicked.
Original PR description
## Description of the issue/feature this PR addresses: On tablet, when a pointing device is used, the cursor on menu items is text ## Current behavior before PR: The cursor shows as "text" when hovering menuitems in the mobile navbar. ## Desired behavior after PR is merged: The cursor shows as "pointer" when hovering menuitems in the mobile navbar.
Required statusbar fields now display the same red border and background warning as other required fields when a user tries to save without choosing a value. This makes validation errors easier to notice and helps users correct forms before saving.
Original PR description
**task:** 6573463 **Description of the issue/feature this PR addresses:** The problem occurs when a field, displayed with the statusbar widget, is required, but the user wants to save without selecting a value. The red colors displayed on the normal field are not applied to the statusbar. This commit adds the required css style to apply the invalid colors. The modification is applied to all media breakpoints. **Current behavior before PR:** The red color is not applied on the border and background of the statusbar when it is invalid. **Desired behavior after PR is merged:** The red color is applied on the border and background of the statusbar when it is invalid. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fixes issues in automated checks for purchasing and units of measure so they work consistently in different run modes and fresh databases. It helps ensure the purchase catalog correctly shows unit of measure information when that feature is enabled.
Original PR description
> ### [FIX] purchase: tour trigger > This commit replaces a trigger which used the button URL because this button's URL can differ if the tour is run in debug mode (eg.: `/odoo/purchase?debug=assets`…
> ### [FIX] purchase: tour trigger > This commit replaces a trigger which used the button URL because this button's URL can differ if the tour is run in debug mode (eg.: `/odoo/purchase?debug=assets` instead of `/odoo/purchase`). > ### [FIX] uom: correct group > This commit fixes `_enable_uom` and `_disable_uom` `UomCommon` class methods to correctly enable/disable the UoM feature. > > Before that, the user has CRUD accesses to UoM but the feature wasn't enabled as expected, which means `_enable_uom` wasn't enough to display UoM fields in view when this field use the group `uom.group_uom` to be display. > > This issue was spotted while working on the `purchase` test/tour `test_catalog_vendor_uom`. When launch locally on a DB without demo data and only with `purchase` installed, the units of measure weren't visible during the tour, and if the tour is paused and we go in the settings, we can see the UoM setting is unticked. Forward-Port-Of: odoo/odoo#289345 Forward-Port-Of: odoo/odoo#283451
This fixes an error that could appear when refusing an applicant while sending a refusal email. Recruiters can now complete the refusal process normally, even after the applicant record is archived.
Original PR description
Steps to reproduce: - Open the Recruitment app and select an applicant. - Make sure "Send Email" is active. - Click on "Refuse". - A traceback is raised (ValueError: Expected singleton). Cause: In…
Steps to reproduce: - Open the Recruitment app and select an applicant. - Make sure "Send Email" is active. - Click on "Refuse". - A traceback is raised (ValueError: Expected singleton). Cause: In `action_refuse_reason_apply`, the applicant is archived (`active = False`) before the refusal email is actually sent. When the code proceeds to send the email via `_prepare_send_refusal_mails` in the `applicant.refuse.single` wizard, it accesses the computed `applicant_id` field. Because the applicant is now archived and the compute method reads `self.applicant_ids` without `active_test=False` in the context, it returns an empty recordset. Calling `message_post` on this empty recordset triggers the error. Fix: Pass `active_test=False` in the context when evaluating `self.applicant_ids` inside `_compute_applicant_id` so the wizard can still locate the newly archived applicant. task-6574551 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
This fixes how copied or linked document attachments are referenced so deleting a source item does not leave broken links or remove related business documents unexpectedly. It improves reliability for Documents, Accounting documents, and Sign workflows that reuse or copy attachments.
Original PR description
The `original_id` field is set to `ondelete="cascade"`. The field is meant to mean "derived from" so that when the original attachment is deleted, then the derived attachments are also removed. Which means that after copying, the original would be deleted. Before we may introduce support for ondelete in the ORM, the deletion of the sign template in test_create_update_copy_unlink_template is deleting the linked sign document implicitely leaving the attachment with an invalid reference. See `test_correct_reference_doc_set`.
This fixes an issue where edited sales order line labels could be lost before the order was saved. Sales teams can now trust that custom product descriptions entered on a quote or order remain in place.
Original PR description
In c5037bb, we introduced the `label` field to display the combination of the product name and description. It is a computed field whose inverse sets `name` based on whether a product is selected on the SOL. In some cases, another onchange can be triggered before the inverse method is called, causing the `label` value to be recomputed and reset. This can happen, for example, when a sale order onchange is triggered before the record is saved. Call `_inverse_label` from the `label` onchange so that changes to `label` immediately update `name` and are not lost by subsequent onchange calls. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#290276
This update standardizes the appearance of several popover panels in Odoo Mail, including avatar cards, recipients, mark-as-done, and activity assignment popovers. Users get a more consistent and polished interface across related communication actions, including in dark mode.
Original PR description
This PR centralize the popover style and apply it to avatar_card, recipients, markasdone and activity assign popover. ## Before: <img width="504" height="242" alt="image" src="https://github.com/user-attachments/assets/a20e20c7-3d1c-4b5e-b9e1-313e71f956c7" /> <img width="623" height="466" alt="image" src="https://github.com/user-attachments/assets/516b08d8-2e4a-4a11-a807-84bbd803bd30" /> ## After: <img width="545" height="202" alt="image" src="https://github.com/user-attachments/assets/2caecb5d-f751-4c29-9d15-998ba0d9fd59" /> <img width="625" height="439" alt="image" src="https://github.com/user-attachments/assets/404de351-e0e1-48be-863f-2e675dd57275" /> Forward-Port-Of: odoo/odoo#290243
Website theme setup now shares whether the selected color palette is dark, allowing theme-specific setup steps to choose page options that match the user's palette. This helps newly configured websites look more consistent with the selected visual style.
Original PR description
Before this commit, a theme post-copy hook could not know whether the palette selected in the configurator was dark. Theme-specific page options could therefore not adapt to the selected palette. After this commit, the configurator passes the palette mode in the theme setup context so theme-specific hooks can use it. Forward-Port-Of: odoo/odoo#290161
Italian invoices using the Import/Export fiscal position now apply the correct 0% tax instead of adding both standard and N7 zero-rate taxes. This prevents incorrect tax setup on invoice lines and supports more accurate Italian accounting and e-invoicing data.
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
Attendance officers without full Employees app access can now open the Employees menu from Attendance without hitting an access error. The menu now shows an attendance-specific employee view with only the information they are allowed to see, improving usability while keeping HR data restrictions in place.
Original PR description
A user configured with "Officer: Manage all attendances" but no access to the Employees app can see the "Employees" entry under Attendances > Overview, since that menu only requires Attendance…
A user configured with "Officer: Manage all attendances" but no access to the Employees app can see the "Employees" entry under Attendances > Overview, since that menu only requires Attendance rights. Opening it, however, raises an access error naming the "Current Time Off Type" field. Steps to reproduce: ------------------- * Go to Settings > Users, open a user and set their access rights to: Employees app: no access, Attendances app: "Officer: Manage all attendances" * Log in as that user * Go to Attendances > Overview > Employees > Observation: Error: "You do not have enough rights to access the field "current_leave_id" on Employee (hr.employee). Please contact your system administrator." Why the fix: ------------ The "Employees" menu pointed to `hr.open_view_employee_list_my`, the full HR Employees action (model `hr.employee`, no view_id override), which resolves to the same default kanban view used by the Employees app. That view is extended by hr_holidays to embed `current_leave_id` (and other Time Off fields), declared with `groups="hr.group_hr_user"` on the model. That group restriction is enforced by the ORM on read, independently of whether the field is actually shown in the view, so any attendance-only officer opening the menu had that read rejected outright. The menu now points to `hr_employee_attendance_action_kanban`, an attendance-scoped action already shipped in the module for this exact purpose: it uses the `hr.employee.public` model with a minimal kanban view (name, avatar, job, work location, check-in state), none of which require HR app access, restoring the ability to browse employees from the Attendance app without needing `hr.group_hr_user`. opw-6488582 Forward-Port-Of: odoo/odoo#289884 Forward-Port-Of: odoo/odoo#287140
Website editing controls and the shop product comparison bar now handle longer translated labels more reliably. This prevents layout issues and missing styling for users working in languages such as German, improving consistency across localized websites.
Original PR description
Steps to reproduce: - Set the user language to German. - Open a color picker with the `Theme` tab in the website editor. - Check the color presets and the reset button. - Open the product comparison bar on the shop page. => Long labels do not fit and some styles are missing. Before this commit, long labels did not fit in the color preset picker. Some CSS selectors also relied on English `title` values, so their styles were not applied in other languages. After this commit, the preset picker adapts to long labels and the CSS selectors use dedicated classes that work in every language. task-6259086 Forward-Port-Of: odoo/odoo#289308 Forward-Port-Of: odoo/odoo#286426
This fixes the loyalty program setup so Buy X Get Y promotions no longer show or allow minimum purchase settings. It prevents users from configuring an option that should not apply to this promotion type, reducing confusion and setup errors.
Original PR description
I think the point was to hide the entire `Minimum Purchase` section when the program type is `buy_x_get_y`, but only the label is hidden. This commit will also hide the div under the label, so no minimum purchase can be set on `buy_x_get_y` programs --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#288281
Fixed a visual issue in Sales quotations where the optional products table could appear lighter than its surrounding area in dark mode. This keeps the quotation modal looking consistent and easier to read for users who prefer dark mode.
Original PR description
**Steps to reproduce:** - Set preferences to dark mode - Create a quotation and add a product with optional products (e.g customizable desk) -> Background of optional products is lighter than the…
**Steps to reproduce:** - Set preferences to dark mode - Create a quotation and add a product with optional products (e.g customizable desk) -> Background of optional products is lighter than the surrounding div **Behavior:** The `div` showcasing optional products is set to be a bit darker to add contrast in the modal. In light mode, table's background is transparent, which allows it to adapt to a darker container. However, this is not the case in dark mode, which causes a mismatch between table and div backgrounds. By default `$table-bg` follows `$body-bg`: https://github.com/odoo/odoo/blob/3442814d57cd9420d7dc6d022d15cd5d1b3def74/addons/web/static/lib/bootstrap/scss/_variables.scss#L738-L740 And is later set to transparent here: https://github.com/odoo/odoo/blob/3442814d57cd9420d7dc6d022d15cd5d1b3def74/addons/web/static/src/scss/bootstrap_overridden_frontend.scss#L74-L75 However when darkmode is enabled, `$body-bg` is re-assigned, which forces `$table-bg` back to the default dark color, bypassing the transparent override. https://github.com/odoo/odoo/blob/3442814d57cd9420d7dc6d022d15cd5d1b3def74/addons/web/static/lib/bootstrap/scss/_root.scss#L132-L139 --- This commit ensures that `table-bg` is explicitly set to transparent for tables displaying optional products. opw-6569713 Forward-Port-Of: odoo/odoo#288127
The website setup flow now keeps future-step fields unavailable until users reach the relevant step. This prevents hidden fields from reacting to mouse, keyboard, or screen reader interaction, making the configurator clearer and more accessible.
Original PR description
Steps to reproduce: - Start the website configurator and open the description step. - Before choosing a website type, move the pointer over the area where the industry field will appear. - Navigate with Tab before completing the industry selection. => Hidden fields still react to input and can receive keyboard focus. Before this commit, the industry input and positioning dropdown were transparent until the previous step was complete. They could still react to pointer input and be announced by screen readers. After this commit, these fields stay hidden and unavailable until their respective steps are reached, while keeping their layout space. Forward-Port-Of: odoo/odoo#290297
The Bulgarian SAF-T report will now only be available and automatically installed when the advanced accounting module is installed. This prevents the report from appearing in setups that are not intended to use advanced accounting features.
Original PR description
As the Bulgarian SAF-T Report is destined for advanced accounting, it should only be available and auto-installed when the accountant module is as well. Forward-Port-Of: odoo/enterprise#132731
Kenya eTIMS reporting now excludes taxes that do not have a KRA tax code from the reported tax-inclusive total. This prevents levies owed to other authorities, such as tourism levies, from being incorrectly included in tax authority submissions.
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
The working file card in accounting reports now displays its menu button without overlapping the status button when selected. This small visual fix makes the card easier to read and interact with, reducing confusion for users managing audit working files.
Original PR description
Slightly improve the style of the kanban card of the working file to make the 3-dots button not on top of the state button when pressed. Forward-Port-Of: odoo/enterprise#132789
The account return guided test flow has been updated after the removal of a setup wizard. Returns are now generated manually in the test flow, helping keep automated checks aligned with the current product behavior.
Original PR description
With the removal of the configuration wizard, we have to remove those steps in the tours. In consequences, the return generation trigger has been changed, so they need to be manually generated. This commit fix partially the tours in addition to https://github.com/odoo/enterprise/pull/131928/changes which fixes the rest of the flow. Forward-Port-Of: odoo/enterprise#132134
Fixed an issue that could block users from opening the rental order lines schedule after all variants of a rental product were deleted. The schedule now opens safely without trying to preselect a missing product variant, reducing disruption for rental workflows.
Original PR description
Currently, an error occurs when opening the Rental Order Lines Schedule view. **Steps to Reproduce:** - Install the `sale_stock_renting` module. - Go to `Settings` and enable `Variants`. - Go to…
Currently, an error occurs when opening the Rental Order Lines Schedule view. **Steps to Reproduce:** - Install the `sale_stock_renting` module. - Go to `Settings` and enable `Variants`. - Go to `Rental` > `Products` and create a product. - In the `Attributes & Variants` tab, add an attribute with two values and save. - Delete all variants using the `Variants` smart button or from `Inventory` > `Products` > `Product Variants`. - Return to the `Product` and click the `In Renting smart button`. `IndexError: list index out of range` When a product template is created, a product variant is automatically generated if the product has no attributes. Deleting this variant also deletes the product template [1]. By explicitly creating attribute values, a dynamic product variant is generated. Deleting this variant does not delete the product template because of the dynamic attribute [2]. When the In Renting button is clicked, it it going to open the rental order lines Schedule view and adds default_product_id to the action context. Since no product variants exist anymore, accessing the default product variant raises an error [3]. This commit ensures that default_product_id is not added to the context when the product template has no product variants [1]: https://github.com/odoo/odoo/blob/1f70b81eeebcc62b64c18772915e2f4696e189e7/addons/product/models/product_product.py#L486 [2]: https://github.com/odoo/odoo/blob/1f70b81eeebcc62b64c18772915e2f4696e189e7/addons/product/models/product_product.py#L478-L480 [3]- https://github.com/odoo/enterprise/blob/98ec35f3f17a2b706ad4fcc4d6161d12d05eadfd/sale_renting/models/product_product.py#L69 [4]: https://github.com/odoo/odoo/blob/942d3892c33e7ccdcfec260c3da37095069b699e/addons/stock/models/product.py#L635-L643 [5]: https://github.com/odoo/odoo/blob/942d3892c33e7ccdcfec260c3da37095069b699e/addons/stock/models/product.py#L601-L612 sentry-7637715724 Forward-Port-Of: odoo/enterprise#132650 Forward-Port-Of: odoo/enterprise#126356
The Australian payroll onboarding process now correctly accepts bank details when a BSB and bank name are provided, even if the BIC field is empty. This prevents users from seeing an incorrect warning after entering valid local bank information.
Original PR description
Bug reproduction: 1 - Install l10n_au_hr_payroll_api, settings→payroll→AU localization 2 - Start payroll onboarding `2.1 - Next step→fill in BSB and keep BIC empty→Set Bank details` 3 - No BSB or bank set warning continues to appear Bug cause: 1 - For that warning, there is check that checks bic (to not keep empty) Bug solution: 1 - bic check is removed and bank name check is added task-6540863 Forward-Port-Of: odoo/enterprise#131463 Forward-Port-Of: odoo/enterprise#130792
Dutch VAT returns and ICP declarations could fail when companies used a password-protected Digipoort private key. The update reads the key in the expected unencrypted form so submissions and status checks work again.
Original PR description
Steps to reproduce: 1. Set a Digipoort certificate whose private key has a password 2. Submit a VAT return or an ICP declaration 3. It fails with 'bad password read' Analysis: Before 19.0 the PEM key was in an unencrypted format. Since f88f8258ead, env['certificate.key'].pem_key is encrypted whenever the key has a password. Every consumer in this module loads it without a passphrase: the VAT wizard, the ICP wizard and the status polling cron. Same cause as (odoo/enterprise#96562), which fixed it for l10n_mx_edi. Solution: Decrypt the key when reading it, as was already the case before 19.0. opw-6421300 Forward-Port-Of: odoo/enterprise#132023 Forward-Port-Of: odoo/enterprise#127528
The payroll salary test was updated to match current behavior after a removed benefit allocation feature, a display change, and a corrected public transport value. This helps keep automated checks reliable and reduces false failures in payroll-related validation.
Original PR description
Error 1:
Drop the automatic extra legal allocation 's test: this feature was remove
in this task 5362345; but the test was not removed
Error 2:
Due to some UX change the IP display change and the test was not up-to-date
Error 3:
Due to a misconfiguration the public transport value was wrong.
runbot_error-242808
Forward-Port-Of: odoo/enterprise#132227
Forward-Port-Of: odoo/enterprise#131958Fixed an issue where Payroll dashboard warning cards stayed visible after users chose "Never show it again" until the page was refreshed. Dismissed warnings now update immediately on screen, reducing confusion for payroll users.
Original PR description
Bug reproduction: - Versions 20.0 and above - Go to the Payroll dashboard - Hover a warning card - click the cross confirm with "Never show it again" - The card stays on screen until the page is…
Bug reproduction: - Versions 20.0 and above - Go to the Payroll dashboard - Hover a warning card - click the cross confirm with "Never show it again" - The card stays on screen until the page is refreshed Bug cause: Dismissing a warning no longer soft reloads the dashboard: the dialog calls the `onDismiss` callback given by the dashboard, which fades the matching cards out and refreshes the cached warnings. However, `onDismiss` was never declared in the props of ArchiveWarningDialog. This was harmless with `static props`, as `this.props` was the object passed by the parent, but since the conversion to `useProps`, `this.props` only holds the declared keys. The callback silently resolved to `undefined`, so the record was archived server side but nothing was dispatched client side. - conversions of props in below PR: -- https://github.com/odoo/enterprise/pull/131078 Bug solution: - Declare the onDismiss props so the dismissal is dispatched again. task-6585492 Forward-Port-Of: odoo/enterprise#132218
Accounting users in Chilean companies can now upload invoice XML files without administrator rights blocking the import. This prevents invoices from being created without the attached XML being processed, reducing manual follow-up and support needs.
Original PR description
Scenario: - be not an admin but have access to accounting - switch to chilean company - go to customer invoices - click on Upload and upload an XML file Result: an invoice is created, but the XML is not treated because of this permission error: 19.0/l10n_cl_edi/…/account_move.py", line 1078, in _l10n_cl_import_dte invoice.l10n_cl_dte_file = file_data['attachment'] odoo.exceptions.AccessError: You do not have enough rights to access the field "l10n_cl_dte_file" on Journal Entry (account.move). Please contact your system administrator Cause: l10n_cl_dte_file field is only accessible to administrator. opw-6509550 Forward-Port-Of: odoo/enterprise#131575 Forward-Port-Of: odoo/enterprise#130416
Customer payments in the Mexican electronic invoicing module now correctly inherit the payment method set on the selected bank journal. This prevents payment complements sent to the tax authority from using the default bank transfer method when another valid method, such as credit card, was configured.
Original PR description
Currently, payment way configured on a bank journal is not taken into account, payments will default to "03 Transferencia electrónica de fondos". Steps to reproduce: - Set the "Payment Way" of a bank journal to "04 Tarjeta de Crédito". - Manually create a customer payment in that journal - Look at the "Payment Way" of the payment, then send the payment complement (REP) to the SAT. Issue: The payment way is "03 Transferencia electrónica de fondos" and the REP carries FormaDePagoP="03" The one set on the journal is ignored. Analysis: We should evaluate the journal before the transferencia default so a payment inherits the payment way, and keep transferencia as the last possible value. opw-6493514 Forward-Port-Of: odoo/enterprise#132074 Forward-Port-Of: odoo/enterprise#130133
Australian Payroll users can now add or remove people from payroll groups through the Groups form without causing a save error. These membership changes are also consistently audit-logged, improving traceability for payroll administration.
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#125124This fix ensures payroll accounting entries that have already been posted are handled with the appropriate reduced access rights. It helps keep payroll accounting processes reliable while avoiding unnecessary elevated permissions after entries are finalized.
Original PR description
Forward-Port-Of: odoo/enterprise#132827 Forward-Port-Of: odoo/enterprise#132624
This fixes an issue where the website builder view could unexpectedly shift when a chat message was sent while editing a partially visible element. The change keeps the editing overlay aligned and prevents empty space from appearing, making website editing more stable.
Original PR description
The builder could shift upward when sending a chat message while a partially visible element was selected. The selection overlay can extend beyond the visible area, causing the builder layout to become programmatically scrollable. When the chat calls `scrollIntoView`, the parent layout is also scrolled, while the preview frame remains unchanged, causing the overlay to become misaligned and leaving empty space. Use `overflow: clip` instead of `overflow: hidden` on the builder layout container. This keeps the existing clipping behavior while preventing programmatic scrolling caused by the overlay's overflow. The fix is applied in the website module layout since the issue is caused by the builder container being scrollable, rather than by the chat itself. task-6229153
The Live Chat channel card layout was adjusted so the Join or Leave button stays clear of the three-dot card menu. This prevents visual overlap when users hover over a card, making the action button easier to read and use.
Original PR description
The three-dot menu of a kanban card sits in its top-right corner, where the Join/Leave button of a Live Chat channel also sits. Hovering the card brought the menu over the right edge of the button. This commit widens the padding of the button column from pe-1 to pe-4 to avoid this overlap. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fixes an issue where links that were made bold by a stylesheet could not be changed back to normal text in the editor. Business users editing email or website content can now reliably adjust link formatting without needing technical help.
Original PR description
Problem: Links with `font-weight: bold !important` from a CSS stylesheet cannot be unbolded from the editor. Cause: After `2028bc00f177d3fcb1e1dc6304153f9ebe0a523a`, applying a style to a link always wraps it in a `span`. When the link itself has a `font-weight: bold !important` rule, the style on the `span` cannot override it. Solution: Apply the style directly to the link, or more generally to any unsplittable element, so the new style can override the existing CSS. Steps to reproduce: - Open a new Email Marketing. - Select the "Welcome Message" template. - Add a link and observe that it is bold by default. - Try to unbold the link. - Observe that nothing happens. task-xxxx --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#289922
The website shop now blocks combo products from being added to the cart unless every required choice is properly selected. This prevents customers from checking out with incomplete combo orders, even if browser controls are bypassed.
Original PR description
Steps to reproduce: =================== 1. Publish a combo product whose choices each offer more than one item, so the combo configurator is shown. 2. On the shop, open the product and click "Add to…
Steps to reproduce: =================== 1. Publish a combo product whose choices each offer more than one item, so the combo configurator is shown. 2. On the shop, open the product and click "Add to Cart". 3. Select an item for one combo choice only. The dialog's "Add to cart" button stays disabled. 4. Remove the `disabled` attribute from that button with the browser developer tools and click it. => The combo is added to the cart with one of its choices unanswered, and the order can be paid in that state. Root cause: =========== The incomplete selection is only prevented on the client side, by disabling the button until every choice has been answered. Server side, `/website_sale/combo_configurator/update_cart` only rejects a completely empty selection, never that the selected items cover every choice. Fix: ==== Reject the request unless the selected combo items cover exactly the combo choices of the product. Comparing the set of choices rather than counting the items also rejects a selection answering the same choice twice while leaving another one unanswered. opw-6478837 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#289886 Forward-Port-Of: odoo/odoo#283465
The Time Off Ledger now shows expected working hours based on each employee's actual schedule for the specific day, instead of repeating a weekly average. This makes reports accurate for staff with shorter or longer scheduled days, improving attendance and time off tracking.
Original PR description
The Time Off Ledger report shows the same "Expected Hours" value for every working day of an employee, even when their working schedule assigns different hours to different weekdays. ### Steps to…
The Time Off Ledger report shows the same "Expected Hours" value for every working day of an employee, even when their working schedule assigns different hours to different weekdays. ### Steps to reproduce: 1) Install hr_holidays_attendance. 2) Create/assign a working schedule where daily hours vary across the week (e.g. Monday-Thursday 8.5h, Friday 5h). 3) Go to Attendance > Reporting > Time Off Ledger, filter on that employee. ### Observed behavior: "Expected Hours" is identical on every day (the schedule's average hours/day), regardless of which weekday the row is for. ### Expected behavior: "Expected Hours" should match the hours actually scheduled for that specific weekday, so a shorter Friday shows less than a full Monday. ### Root cause: `Time off Ledger` is a SQL view. Its `_select()` builds `expected_hours` from `rc.hours_per_day` at [1], i.e. `resource.calendar.hours_per_day`, a field explicitly labelled **"Average Hour per Day"** and is computed via [_get_hours_per_day] as `hours_per_week / days_per_week`, a single flat value for the whole calendar. The per-weekday hours are available in `resource.calendar.attendance` it stores `dayofweek`, `hour_from`/`hour_to` and a computed `duration_hours` per line, and can legitimately differ per weekday (e.g. Monday 8h vs Friday 4h) at [2]. The report's own [_cte_cal_workday()] CTE already reads this table to decide whether a weekday is a working day (`cal_workday`, joined as `cw` in `_from()`), but discarded the actual hours, keeping only `(calendar_id, dayofweek)`. `_select()` then fell back to the calendar-wide average via `rc.hours_per_day` instead of the per-day value. Example: calendar with Monday 8h and Tuesday 4h -> `hours_per_day` averages to 6h; the report showed 6h on both Monday and Tuesday instead of 8h and 4h respectively. [1]- https://github.com/odoo/odoo/blob/5568f6e472e2e53bc2931e744421015b0f0f3550/addons/hr_holidays_attendance/report/hr_leave_attendance_report.py#L256 [_get_hours_per_day]: https://github.com/odoo/odoo/blob/5568f6e472e2e53bc2931e744421015b0f0f3550/addons/resource/models/resource_calendar.py#L703-L707 [2]- https://github.com/odoo/odoo/blob/5568f6e472e2e53bc2931e744421015b0f0f3550/addons/resource/models/resource_calendar_attendance.py#L15-L31 [_cte_cal_workday()]: https://github.com/odoo/odoo/blob/5568f6e472e2e53bc2931e744421015b0f0f3550/addons/hr_holidays_attendance/report/hr_leave_attendance_report.py#L82-L89 ### Fix: `_cte_cal_workday()` now aggregates `SUM(duration_hours)` per `(calendar_id, dayofweek)` from `resource_calendar_attendance`, instead of just selecting the distinct keys. `_select()` reads this per-weekday value (`cw.hours_per_day`) instead of the calendar-wide `rc.hours_per_day` for both `expected_hours` and `difference_hours`. **opw-6425167** Forward-Port-Of: odoo/odoo#289812 Forward-Port-Of: odoo/odoo#280664
The mail and live chat action controls were reorganized into clearer reusable parts, including dedicated button and dropdown handling. This is an internal cleanup that should make future maintenance and improvements easier without changing the main user experience.
The mail and live chat action menus were reorganized to make the underlying interface components cleaner and more consistent. This should support easier maintenance and more reliable future improvements with only minor visible changes, such as button alignment and rounded styling.
This update simplifies the mail welcome page so it loads in a more predictable way. The change is internal and should not alter the user experience, but it helps keep the Discuss area easier to maintain.
Original PR description
task-6373278 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