Thursday, August 27, 2026
26 changes · master
Enhancements to existing features
New Google fonts added to a website are now hosted locally instead of being served by Google. This improves page performance scores and helps reduce privacy and GDPR compliance concerns, while also improving how fonts load for visitors.
Original PR description
Currently, Google fonts are served by Google, which lowers the Lighthouse score and may impact GDPR compliance. Solution: By default, when a user add a new Google font, it is hosted locally. Task-6009931
The calendar attendee invitation flow is now simpler and easier to use, with clearer labels, better field ordering, and a smaller dialog. Users can also add attendees more smoothly from quick event creation, including by entering an email address for a new contact.
Original PR description
# Purpose Simplify the attendee invitation wizard a bit & make the attendee pill display in the quickcreates clickable # Specs Event form: - Align invitation buttons with guest count - Clearer attendee placeholder Invitation wizard: - Reorder fields - Move default focus to email - Remove contact image Quickcreate event: - Display attendee pill - Opens invitation wizard for new partners --------------------------------- Task-6209447
Website managers can now edit common HTTP error pages directly in the website builder, including changing layout, content, and whether the default error message appears. The update also improves how website content routes are listed, helping modules expose dynamic pages more clearly for discovery and editing.
Original PR description
This PR improves website content discoverability and website customisation by: - Extending list_as_website_content to support dynamic, structured routes. - Making HTTP error pages editable through…
This PR improves website content discoverability and website customisation by: - Extending list_as_website_content to support dynamic, structured routes. - Making HTTP error pages editable through the website builder. # Dynamic structured routes for `list_as_website_content` Previously, `list_as_website_content` only supported returning a static title, with route URLs inferred automatically from the endpoint. This PR extends the API to also accept callables returning structured route definitions (`route_title` and `route_url`), enabling explicit and dynamic website content entries. This provides greater flexibility for modules exposing multiple or computed website routes. # Editable HTTP error pages HTTP error pages (400, 403, 404, 415, and 422) are now editable from the website builder via: `/website/http_error/<error_code>` ### Users can: - Fully customise error pages using snippets and inner blocks. - Toggle the visibility of the default error message. - Preview and edit pages using a demo error card in edit mode instead of triggering a real HTTP error. task-4714826 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Odoo now lets users and business workflows filter uploaded binary files by their stored filename or file size. This preserves file-name based filtering even as separate filename fields are replaced by the binary field itself.
Original PR description
Add `filename` and `size` as properties that can be used when searching binary fields. Since file name fields can be replaced by just using the binary field, we provide this to be able to search by the name of the file.
`[('bin_field.filename', 'ilike' 'test')]` searches for binary values with file name containing "test".
----
Since we remove the fields (https://github.com/odoo/odoo/pull/284302) and may want to continue support filtering on the file name.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prThe employee records timeline now displays contract periods more clearly and avoids confusing visual states. This makes it easier for users to understand which version is selected and how contract versions connect over time.
Original PR description
Adapting the misc widgets to the new design versions_timeline.scss as unused styling, but that file owned the timeline's own geometry, and the new markup kept the item wrapper class the statusbar had…
Adapting the misc widgets to the new design versions_timeline.scss as unused styling, but that file owned the timeline's own geometry, and the new markup kept the item wrapper class the statusbar had renamed in the meantime The employee records bar ended up with one contract line per version, drawn inside the bar, instead of a single line spanning the versions of a contract; with a selected version painted in the very grey the statusbar paints on hover, so a hovered version looked selected; and with items never folding into the dropdowns, since the statusbar looks them up by ".o_arrow_button_wrap": the bar wrapped onto a second row and showed a stray duplicate of the selected version. Give the bar a stylesheet again, scoped to a class shared with the other versioned records bars: only the displayed version is highlighted, and the contract line bridges the gap between two versions of the same contract so it reads as one line under the bar. task-6510183 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
After installing VoIP, users are now taken directly to the phone number list so they can continue setup more easily. The update also clarifies that phone numbers still being processed will refresh automatically, reducing confusion during provisioning.
Saudi payroll now lets companies choose how service duration is calculated for end-of-service benefits: 360 days, 365 days, or actual days in the year. This supports different company policies and improves payroll configuration accuracy for Saudi employees.
Original PR description
Replace the Saudi EOS actual-days boolean with a selection allowing companies to compute service duration using 360 days, 365 days, or the actual number of days in the year. Updated the employee payroll view and EOS tests accordingly. task-6413322
Businesses can now set a maximum bookable capacity for each appointment time slot, helping avoid too many reservations arriving at the same time. This is useful for capacity-sensitive services such as restaurants, and the limit is also reflected in Google Reserve availability.
Original PR description
Allow businesses to configure a max bookable capacity, applied for every slot computed from availabilities. This prevents accepting too many reservations at once and allows some pacing. This is…
Allow businesses to configure a max bookable capacity, applied for every slot computed from availabilities. This prevents accepting too many reservations at once and allows some pacing. This is different from the availability of resources, and is for instance designed for restaurants to avoid clogging the kitchen. The feature is also supported in appointment_google_reserve, and code is adapted to make sure we compute this availability even when selecting manually a given resource (e.g. for resource_time) The heuristic is the following: --- 0. Only for resources, and when managing capacity, for a recurring appointment... 1. For every appointment.slot... 2. 'Subslots' will be created, as usual, every slot_creation_interval. We are using this as the duration of the interval over which we limit the bookings to slot_interval_capacity. The last subslot will also use this value, no matter the appointment_duration. 3. To count how much capacity is currently used on a subslot, we count reserved capacity on booking lines of meetings STARTING in the interval [start, start + slot_creation_interval[. We include the start, as this is the most common use case when booking and matches booked time on the front-end, and exclude the ending as next subslot would start there. Example --- Let us have an appointment configured as follows to illustrate: - slot_interval_capacity = 10 - slot_creation_interval = 15 min - appointment_duration = 1h - 1 appointment.slot: 19.00 to 20.30 - 22 total capacity available on available resources -> 'subslots' are 15 min long and created at 19.00 19.15 19.30 Now, let's add bookings one by one: - From the backend, 2 people at 19.25 - 6 people at 19.00 - 8 people at 19.00. Not enough capacity. They book at 19.15. The subslot [19.15, 19.30[ is now full, as the 19.25 booking also counts. - 4 people at 19.00. Subslot [19.00, 19.15[ is now full. - 4 people. They cannot book because total capacity is already used up to 20/22. They can only book for two, and end up booking the 19.30 subslot. While that subslot is not full in the sense of slot_interval_capacity, the day is now full. Algorithm --- In order to lower the time complexity of the check on booking lines, we implement a sliding window of subslots over booking lines grouped by start. This should end up in O(nlogn) (due to sorting, see below) instead of O(n^2). As this only works with ordered data, we order booking line data (after grouping, more efficient) and slots (only if the computation is needed, a few explicit checks are made for this) in an ascending order of start datetime. Test --- A test is added for both appointment and appointment_google_reserve. In the appointment test, we also include a complex configuration as we want the sliding window algorithm to be robust and work in any configuration. Other change --- To complete this new feature, we enable the total row in the gantt view for appointments. We use the total_capacity_reserved instead of the usual count. We only compute the total row(s) when on a single appointment to avoid clash of definition when manage_capacity is true / false. Task-6191497
Category header display settings are now managed at the website level instead of separately on each product category. This helps keep the shop experience consistent across all categories on the same website and reduces configuration confusion.
Original PR description
Before this commit, category header settings were stored on each product category, leading to inconsistent behavior across categories within the same website. This commit stores these settings on the website instead, making them consistent for all categories of a website. Upgrade PR:https://github.com/odoo/upgrade/pull/10604 task-6325882
Property fields can now decide individually whether their changes are recorded in the chatter. This gives businesses more control over which property updates are visible in communication history, helping reduce noise while preserving important audit trails.
Original PR description
Allow to track properties. Properties fields are all "tracked" but the property have their own tracking attribute that will define if the change are tracked or not in the chatter. TASK-5131127 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Belgian payroll now shows more complementary benefit information on payslips and improves how insurance contributions are configured and validated. This helps payroll teams reduce manual inputs, catch invalid insurance amounts earlier, and provide employees with clearer salary details.
Original PR description
Refactor existing Belgian salary rules to support the complementary information display section on payslips and enhance employee insurance configuration. - Add employee-level ambulatory insurance contribution and setting defaults. - Compute employer share for meal vouchers via new `MEAL_VOUCHER_EMPLOYER` rule. - Refactor termination rules (Hospital, Ambulatory, Group Insurance) to compute directly from contract version history instead of manual inputs. - Enable `display_in_pdf_extra_info` across relevant insurance rules. - Rename `F_SOCIAL_CONTRIB` and configure for extra info display. - Add payroll warnings to catch invalid employee insurance contributions. Task: 6327364
The accounting dashboard KPI cards have been refreshed to stay visible and easier to use. On mobile devices, the cards now appear in a horizontally scrollable row, improving access without taking up excessive screen space.
Original PR description
This commit improves the UI of the KPI cards in the account dashboard. There's no longer a close button on the cards, they're meant to always be visible on the dashboard. Also, the cards are now in a scrollable row on mobile, instead of being stacked vertically. Task ID: 6498831
Belgian payroll can now identify when an employee's salary is paid to a bank account owned or managed by someone else. This helps companies capture the required beneficiary details, especially for non-European accounts, improving compliance in exceptional payment situations.
Original PR description
Under specific circumstances, you can have your salary sent to another account, for example, you're under heavy fines and drawbacks, and your salary is managed by a legal advisor. In that case, you're not the proprietary of the account. Moreover, if you're not the proprietary and the account where money is sent is not european, we need to know the beneficiary city + country. Adding 2 new fields on `res.partner.bank` (displayed in form only for BE companies) : - `is_third_party`: computed (editable) boolean checking if `holder_name` and `partner_id.name` are matching or not. - `third_party_beneficiary_id`: res_partner managing the third party account. Task: 6431562
The quotation template form now separates subscription-specific settings into their own column. This makes the form easier to scan and helps users distinguish subscription configuration from general template details when setting up quotations.
Original PR description
Before this change: The quotation template form view displayed subscription specific fields together with the template's general fields in a single column. This made it hard to visually distinguish which fields belonged to the subscription configuration or the general template settings. After this change: The subscription fields are now separated into their own column. This groups related fields visually and makes the distinction between general template info and subscription specific settings clear. Impact: Improves the user experience by making subscription fields easier to locate and distinguish from other template fields, reducing the chance of confusion when configuring a subscription quotation template. task id: 6410262
Datetime fields can now automatically fill in a preset value when a user clicks them. This supports workflows like Social scheduling, where the planned time can default to one hour from now to speed up data entry.
Original PR description
Purpose ======= I social, we would like to automatically set the scheduled date to "now + 1 hour" when we click in the Datetime field. Task-6323897
The spreadsheet dashboard settings panel is now hidden from users who do not have administrator rights. This helps prevent non-admin users from seeing configuration options they cannot or should not manage, making the dashboard experience clearer and more controlled.
Original PR description
Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: task-6345154 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Businesses can now turn an active asset set to no depreciation into a depreciable asset without manually recreating it. The system transfers the current book value to the selected asset account, closes the original asset, creates and validates the new depreciable asset, and makes navigation between the linked records easier.
Original PR description
Allow users to convert a running asset that uses the "No Depreciation" method into a depreciable asset. A new "Activate Depreciation" action is added to the asset modification wizard: - A transfer journal entry moves the book value from the current fixed asset account to a newly selected one. - The old asset is closed and a new asset is created on the target account, inheriting the book value, salvage value, and the depreciation parameters configured on the new account. - The new asset is validated immediately, computing its depreciation board from the activation date. task-6357855
Project sharing now separates collaborators from message followers, so businesses can grant limited task editing access without automatically changing notification followers. This improves control over external or portal user access while keeping project communication settings cleaner.
Original PR description
#TODO --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
HR now skips an unnecessary calendar lookup when employee contract or work versions follow each other without a gap. This improves performance for related HR validations, reducing wait times and database load without changing business behavior.
Original PR description
Optimize `has_work_hours_between_versions` by adding a fast path for back-to-back versions. If a new version starts the exact day after the previous one ends, there is no time gap between them (the old version ends at midnight and the new one begins immediately). In this scenario, we can safely return `False` and bypass the expensive calendar lookup entirely. `._get_l10n_be_min_wage_invalid_employees` on next.odoo.com: | | time | SQL queries | |--------|--------|--------| | before | ~7.8s | 6744 | | after | ~2.4s | 491 | <img width="1874" height="995" alt="image" src="https://github.com/user-attachments/assets/2b61179b-10c5-46a6-a3ac-4a0cad14f6d6" /> <img width="1874" height="995" alt="image" src="https://github.com/user-attachments/assets/7a70fb39-ece9-4090-ba2e-f3c4acca2657" /> task-6472490 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282703
The timesheet ActivityWatch assistant now shows the name of the relevant Odoo record when it can identify one from a visited URL, instead of falling back to a broad app name. This makes time suggestions clearer and helps users recognize what they were working on more quickly.
Original PR description
Before this commit, when the ActivityWatch integration encountered unmatched Odoo URLs, it would fallback to displaying the general application name (e.g., "Working on Sales"). With this commit, if the URL path ends with a valid record ID (e.g., /odoo/departments/1) and the corresponding model can be identified, the assistant will attempt to fetch and display the actual record name (e.g., "Working on Research & Development"). task: 6365568 Forward-Port-Of: odoo/enterprise#127981 Forward-Port-Of: odoo/enterprise#124138
Invoice QR code settings and payment method labels now use the correct local payment scheme names, such as Pix, FPS, PayNow, PromptPay, VietQR, MMQR, KHQR, and SEPA where relevant. This makes setup clearer for businesses in each country and avoids showing SEPA-specific wording where it does not apply.
Original PR description
The QR-code setting on invoices was labelled "SEPA QR Codes" for every country, and the Payment QR-code selection offered "SEPA Credit Transfer QR" everywhere, even where SEPA does not exist. The bank account fields driving those codes were named "Proxy Type" and "Proxy Value", which said little to users. Each localization now names the setting and its QR method after the local payment scheme (Pix, FPS, QRIS, PayNow, PromptPay, VietQR, MMQR, KHQR) and offers it only to companies of that country. SEPA naming is kept for the SEPA zone, other countries get a generic "Payment QR Codes" label, and the bank fields become "Account Identifier Type" and "Identifier Value". task-6471076
Point of Sale manual data reloads now clear browser-stored local and session data in addition to the main offline database. This helps prevent outdated or mismatched information from causing inconsistent behavior after a reload.
Original PR description
Manual data reloads reset IndexDB but leave local and session storage intact. The goal is to clear them to avoid inconsistent data. task-6456447 Forward-Port-Of: odoo/odoo#284238 Forward-Port-Of: odoo/odoo#281456
Point of Sale now lets cashiers move on immediately after validating a paid order instead of waiting for receipt printing to finish. This should make checkout feel faster and reduce delays at the register, while automated checks were updated to match the new flow.
Original PR description
- Stop awaiting the receipt print in the POS after order payment validation - Adapt tours to this behavior change task-id: 6425204 enterprise PR: https://github.com/odoo/enterprise/pull/127818 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283823 Forward-Port-Of: odoo/odoo#280002
Bank journals now receive the right outstanding payment accounts automatically for Moroccan and Indian accounting setups. This helps ensure payments are reflected correctly in cash-basis tax reporting, even when bank synchronization or reconciliation is not available.
Original PR description
Reason: - Moroccan companies usually use cash basis accounting. And the cash basis entries are only made when the invoices are reconciled with the bank transactions. However, in Morocco, there is no…
Reason: - Moroccan companies usually use cash basis accounting. And the cash basis entries are only made when the invoices are reconciled with the bank transactions. However, in Morocco, there is no Moroccan bank available for bank synchronization. Before this commit: - We are not assigning the outstanding accounts on the bank journals by default. - Which is causing the issues when the user creates a payment without an entry and without having any bank transactions to reconcile it with. Therefore, the tax report won't show the moves and taxes that occurred in the period. After this commit: - Introduced a method for updating the accounts on the payment method lines of the bank journal in the account module, as we need the same functionalities in l10n_in as well. - For Moroccan localization, from now on, we are setting the outstanding accounts automatically on the bank journals. - The payment accounts are applied by default during CoA loading and whenever payment method lines are recomputed, ensuring accounts remain consistent. Task-6041119 Forward-Port-Of: odoo/odoo#254642
Module descriptions, summaries, and short labels are now exported and loaded with each individual module instead of being bundled into the core translation file. This makes translations work better for custom modules and avoids extra translation export work when modules are added or updated.
Original PR description
Currently a module's `description`, `shortdesc`, and `summary` that are defined in the manifest file are exported in the `base.pot` file. This means that in order to get them translated (in case of an update or a new module), the `base.pot` file needed to be re-exported again with all the possible modules in the addons paths. For custom modules, this also means that their manifest terms are not translated at all, because their terms are not in the `base.pot` file. This commit changes this by exporting the manifest terms in their own modules' POT file, and loading them from there as well. This way, the manifest terms of custom modules can be translated, and there is no need to re-export the `base.pot` file when a new module is added or updated. We also add a test to check that the custom reader implementation is faster than using `polib`.
Payroll users can now tap a full employee row to select it when reviewing payroll runs on mobile. Tapping the employee avatar opens the employee record, making navigation clearer and reducing selection mistakes on smaller screens.
Original PR description
this commit improves the employee selection in mobile view of hr_version_payrun_list making the click event on the record row to select the record and when the avater is clicked the user will be redirected to the employee form view. task-6469653