Friday, September 18, 2026
117 changes · master
New functionality added to Odoo
This update adds guidance for Odoo skill documentation to use simple ASCII punctuation in comments, messages, and related prose. It also cleans up existing guideline text so translators and reviewers see fewer near-duplicate strings caused only by special punctuation.
Original PR description
**Description of the issue/feature this PR addresses:** The skill library has no guideline about the prose written alongside the code: comments, docstrings, user-facing strings and commit messages.…
**Description of the issue/feature this PR addresses:** The skill library has no guideline about the prose written alongside the code: comments, docstrings, user-facing strings and commit messages. Em dashes keep appearing there. They are absent from the keyboard layouts the codebase is written with, so in practice they arrive by copy-paste or from a generation tool; they cannot be typed back by a reviewer who greps for a comment; and two variants of a translatable literal that differ only in the dash are two terms to translate. The skill files themselves carried 65 of them, plus 4 ellipsis characters. **Current behavior before PR:** - An agent writing or reviewing an addon has no rule on punctuation in comments, docstrings, user-facing strings or commit messages. - The guideline files use the em dash heavily, so an agent reading them picks up the habit from the material that is supposed to correct it. **Desired behavior after PR is merged:** - `odoo-guidelines/guidelines/comments.md` holds one section, registered in the skill table so it is read when a comment, a docstring, a user-facing string or a commit message is written: "Plain ASCII punctuation in comments and messages" states the rule, gives a bad/good example, explains why, and carves out the exceptions (content that is data rather than prose, and stable branches, where fixing punctuation is a cosmetic change and rewording a translatable term breaks its translations). - The guideline files follow their own rule: the 65 em dashes and the 4 ellipsis characters are rewritten as a comma, a colon, a semicolon, parentheses or a new sentence, one by one rather than by a blind substitution. The only occurrences left are in `comments.md`, where the character is the subject of the rule and of its "bad" example. - No guidance changes meaning: the cleanup is punctuation only, so it can be reviewed by reading the word diff (`git show --word-diff=plain`). --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#288034
Employees in Mexico can now attach official CFDI invoice XML files directly to draft expenses. The system uses the stamped invoice data to create or reuse vendor bills and keep amounts and taxes aligned with fiscal requirements, reducing manual errors and compliance risk.
Original PR description
The standard expense flow is incompatible with Mexican fiscal law in two ways: 1. CFDI (electronic invoices) are already registered with the SAT at receipt time — the employee cannot decide when they enter accounting. 2. Amounts and taxes are locked by the government-stamped XML — they cannot be adjusted freely in the expense form. This module fixes both by letting employees attach a CFDI XML to a draft expense. From the XML, the module automatically creates or reuses the existing vendor bill, syncs the amounts and taxes from the CFDI if the expense is to reimbure to employee or sets the bill to pay when using company account. task-4455671
This update adds a standard sign-in and consent flow so approved third-party AI/MCP tools can access Odoo on a user's behalf without seeing their password. It also improves compatibility with newer MCP clients by returning clearer protocol errors when a requested method is not available.
Original PR description
To understand the OAuth flow, check the commit message. task-6312868 Forward-Port-Of: odoo/enterprise#131912
Enhancements to existing features
Blog authors now get a more familiar editing experience, with starter content presented as an editable text block and more control over blog post width. The main blog listing also regains a page title, improving search visibility while still allowing it to be hidden when desired.
Original PR description
- [IMP] website_blog: wrap initial content in a "Text" snippet - [IMP] website, website_blog: allow full container control on blog posts - [IMP] website_blog: add a title on the "All blogs" page Forward-Port-Of: odoo/odoo#289201
Resolved issues and error corrections
When editing an online store product with variants, tags now attach to the variant currently shown on the page instead of the default one loaded first. This prevents saved tags from disappearing after reload and keeps product editing consistent for shop managers.
Original PR description
Versions -------- - master Steps ----- 1. Install eCommerce. 2. Open a product with variants on the shop and enter Edit. 3. Pick another variant, then add a tag in the Tags row and save. Issue ----- The tag lands on the variant the page was loaded with instead of the one being displayed. After reload it is absent from the page, and the editor no longer offers it. Cause ----- `ProductVariantOption` reads `data-product-variant-id`, which is rendered server side for the default variant and never refreshed on combination change. Solution -------- Read `[data-product-id]` inside `.js_product` instead, which follows the displayed combination. opw-testing-day-v20 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#288328
Features or functions removed from Odoo
This change removes obsolete internal code related to unit-of-measure rounding in the Purchase and Sales apps. It has no expected impact on daily workflows, but helps keep the system easier to maintain and reduces technical clutter.
Original PR description
With this commit, remove unused method definitions related to UoM rounding. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Code cleanup and technical improvements
The HR Work Entry module now uses one shared setup for displaying work entry type badges and labels. This reduces duplicated code and makes future maintenance easier without changing the business workflow.
Original PR description
Unify the work entry type rendering logic to eliminate duplicate files and code: - Remove redundant `work_entry_type_badge_field.js` and `work_entry_type_badge_field.xml`. - Extend the `hr_work_entry.WorkEntryType` QWeb template to accept an optional `label` parameter, enabling it to render either a standalone color pill or a pill with an adjacent label. - Move `WorkEntryTypeBadgeField` into `work_entry_type_field.js` to keep all related field registrations in a single component directory. - Update `hr_work_entry.WorkEntryTypeBadgeField` and `hr_work_entry.Many2OneWorkEntryTypeField` templates to call the unified sub-template with their respective data. Task:6578031 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Projects created outside the main Project app flow now automatically receive four basic task stages. This helps users and AI-assisted project creation start with a ready-to-use task workflow, reducing setup omissions after imports or automated project generation.
Original PR description
Before this commit, when the user imports a project he creates he sometimes forgot to import his basic stages to be able to quickly add his task. An AI could also forget to create stages when the user asks the AI to generate a business project. This commit adds a default method to generate 4 basic stages when the project is not created manually by the user in the main action of Project app. task-6233294 Forward-Port-Of: odoo/odoo#287735
PayPal payments now show key account details more consistently and support clearer card brand handling. Businesses also get more control over 3D Secure configuration, helping align checkout behavior with their payment requirements.
Original PR description
1. Add Brands for Card Payment 2. Add possibility to configure 3DS 3. Show account id and email always 4. Remove (copy) from payment methods when duplicated task-6537307 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#288935
Odoo now prevents other workers from loading system registry data while it is being modified. This reduces the risk of inconsistent behavior during internal updates and helps keep multi-worker environments more reliable.
Original PR description
Before modifying a registry, `will_change_registry` is called. During the first call, lock registry loading so that no other worker can load the registry while it's being modified. This is similar to locking during updating of modules. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Odoo search filters can now handle records that span a start and end date, not just records that begin in a selected period. This makes it easier for users to find ongoing items such as events, bookings, or assignments that overlap a chosen timeframe.
Original PR description
A date filter (`<filter date="date_start"/>`) filters on a single field: the periods it offers, as well as the relative ones introduced in [1], match the records that *start* in the searched period.…
A date filter (`<filter date="date_start"/>`) filters on a single field: the periods it offers, as well as the relative ones introduced in [1], match the records that *start* in the searched period.
For models describing a range rather than a single date, it is useful to be able to search for records that are ongoing during a given period.
A date filter can now name the field ending that span:
<filter string="Period" name="period" date="date_start" end_date="date_stop"/>
Its periods and its relative options then match the records overlapping the searched period:
['&', ('date_start', '<=', period_end),
'|', ('date_stop', '>=', period_start),
'&', ('date_stop', '=', False), ('date_start', '>=', period_start)]
A record with no end date ends when it starts. Each bound is serialized with the type of the field it is compared to, so that a date field and a datetime field can be paired.
Task-6546268
[1] https://github.com/odoo/odoo/pull/267980
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-prAccounting users can now use a keyboard shortcut to validate and post an opening entry from the setup wizard. This reduces clicks during initial accounting setup and helps users complete the process more efficiently.
Original PR description
No task ID
This update makes record value changes more efficient by applying field updates in batches instead of one at a time. It also preserves the bank name when setting a bank account on an accounting journal, helping keep financial records accurate.
Original PR description
Set field values in batch instead of doing it field by field. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The spreadsheet component has been updated to the latest available version, bringing ongoing improvements from the shared spreadsheet engine into Odoo. This helps keep spreadsheet behavior current and improves how collaboration/session changes are tracked behind the scenes.
Original PR description
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/4020a44abd [REL] Package: Bump master to 20.1.0-alpha.0 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0) https://github.com/odoo/o-spreadsheet/commit/88a8b225da [IMP] session: Forward root command in the revision payload [Task: 6574631](https://www.odoo.com/odoo/2328/tasks/6574631) Co-authored-by: Florian Damhaut (flda) <flda@odoo.com> Co-authored-by: Anthony Hendrickx (anhe) <anhe@odoo.com> Co-authored-by: Alexis Lacroix (laa) <laa@odoo.com> Co-authored-by: Lucas Lefèvre (lul) <lul@odoo.com> Co-authored-by: Adrien Minne (adrm) <adrm@odoo.com> Co-authored-by: Ronak Mukeshbhai Bharadiya (rmbh) <rmbh@odoo.com> Co-authored-by: Dhrutik Patel (dhrp) <dhrp@odoo.com> Co-authored-by: Rémi Rahir (rar) <rar@odoo.com> Co-authored-by: Pierre Rousseau (pro) <pro@odoo.com> Co-authored-by: Vincent Schippefilt (vsc) <vsc@odoo.com> Co-authored-by: Marceline Thomas (matho) <matho@odoo.com>
The website builder now includes a searchable selector for long option lists, starting with form field types. This makes it faster and easier for users to find the right form field when editing website forms.
Original PR description
*: html_builder This PR introduces a `BuilderSearchSelect` component that has a search functionality, making it easier to find and choose items from large lists of options. It will be initially enabled for the "form field types" selector to simplify picking a field type option. task-5398633 Forward-Port-Of: odoo/odoo#271821
The mail chat composer now has a fully rounded, pill-shaped input when shown on one line. The chat window corners were adjusted to match, giving conversations a more consistent and polished appearance.
Original PR description
Round the composer input to a full pill on a single line. The chat window radius follows so both look consistent. <img width="820" height="718" alt="composer-rounded-comparison" src="https://github.com/user-attachments/assets/23132111-3976-4064-abdb-c7cddae06876" /> Forward-Port-Of: odoo/odoo#287094
Users can now embed whiteboards from Miro, Google Docs, Figma, and Canva directly in supported Odoo content. This makes project tasks and to-do items better suited for collaborative planning and design work without leaving Odoo.
Original PR description
Supported providers: - miro.com - docs.google.com - figma.com - canva.com task-6102610 Forward-Port-Of: odoo/odoo#262181
The working schedules list now displays calendar names vertically aligned with the rest of each row. This small visual improvement makes the list easier to scan and gives the scheduling screen a cleaner, more consistent appearance.
Original PR description
Add a class `o_resource_calendar_list` for the working schedules list view to align the list rows in the middle. Before the PR: <img width="1908" height="597" alt="image" src="https://github.com/user-attachments/assets/19445c28-3e28-4d5b-a12f-f6c1701c01a7" /> After the PR: <img width="1390" height="262" alt="image" src="https://github.com/user-attachments/assets/fb50f6ca-6193-4c5e-9a30-8cd47873f01f" /> task-6562529
Event badges now make key instructions and QR codes easier to use, including when printed and folded. The event session planning experience is also cleaner, with simpler reminder and favorites messaging and fewer confusing badge labels from single-choice questions.
Original PR description
Backport of https://github.com/odoo/odoo/pull/287446 which one is a Forward-Port-Of: https://github.com/odoo/odoo/pull/285915 because freeze v20 meanwhile Several diff for OXP [IMP] event: improve A4…
Backport of https://github.com/odoo/odoo/pull/287446 which one is a Forward-Port-Of: https://github.com/odoo/odoo/pull/285915 because freeze v20 meanwhile Several diff for OXP [IMP] event: improve A4 foldable badge -> required for oxp kenya - if you have ticket instruction, use it on badge + add qr code always visible [IMP] event: don't show tag (question reply) if only one choice -> fix case of "yes, agree" show on badge as tag "yes" [IMP] website_event_track: typo and make it less verbose -> FP quick pass usability [IMP] website_event_track: replace fa-bell by fa-star -> why ? not sure better after... but FP request -> + add menu whishlist directly in event sub menu ## deploy ``` views = [ 'website_event_track.agenda_main_track', 'website_event_track.track_card', 'website_event_track.tracks_search', 'website_event_track.event_track_aside_other_track', 'website_event_track.track_widget_reminder', ] from odoo.upgrade import util for xmlid in views: util.update_record_from_xml(env.cr, xmlid) ``` Forward-Port-Of: odoo/odoo#285915 Forward-Port-Of: odoo/odoo#288790
The PDF quote builder layout is now more consistent and easier to scan. Buttons align with their section titles, multiple buttons fit neatly side by side, and redundant product label text has been removed.
Original PR description
Before this commit, an unnecessary margin on the quote builder buttons left them out of line with their section titles, and those titles didn't match the sections used everywhere else in other tab views. The `Product >` prefix was also redundant, as the product name alone already says what the section is. This commit removes the margin, spaces the buttons so several can sit side by side, aligns the titles with the usual form section style, and drops the `Product >` prefix. task-6528393 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#288523
Product availability searches based on free stock are now much faster, especially in databases with many inventory records. This reduces waiting time and database load when users filter or search products by available quantity.
Original PR description
**Problem:** Searching on free_qty can be slow when there are many stock.move and stock.quant. The search method uses _compute_quantities_dict() to compute the free_qty based on stock.move and…
**Problem:** Searching on free_qty can be slow when there are many stock.move and stock.quant. The search method uses _compute_quantities_dict() to compute the free_qty based on stock.move and stock.quant, which is expensive. **Solution:** A similar field, qty_available, has a faster search method based on stock.quant only. This method can be adapted to support fast searching on free_qty by also aggregating the reserved_qty and subtracting it from the qty_available. **Perf Table:** Record: product.template, with ~20k stock.picking and most products w/o moves. |Record count|Time before|Queries before|Time after|Queries after| |------------|-----------|--------------|----------|-------------| |10k |2.14s |214 |370ms |45 | |50k |6.06s |644 |829ms |50 | |100k |11.42s |1196 |1.05s |46 | opw-6266096 Forward-Port-Of: odoo/odoo#287363 Forward-Port-Of: odoo/odoo#270434
Odoo now installs related country-specific apps when another app for the same single country has already been installed, even if no company is set up in that country. This reduces unexpected missing add-ons, avoids recurring cleanup work, and preserves country metadata used in the Apps screen.
Original PR description
Currently a module with `countries` in the manifest is only installed in case a company with a matching country exists. This commit relaxes the constraint: In case we have already installed a module…
Currently a module with `countries` in the manifest is only installed in case a company with a matching country exists. This commit relaxes the constraint: In case we have already installed a module "from that country" we still install the module. For this we only consider modules that have a single country set in the manifest. (To avoid installing "generic" modules with multiple countries that we do not want.) The current behavior may cause unexpected behavior in case a module is manually installed in case such a company does not exist. (This i.e. causes issues with the runbot tests from time to time) Consider the following case: `l10n_XX`: `countries: ['XX']` `l10n_XX_reports`: `countries: ['XX']` In case we manually install `l10n_XX` but no company has country `XX`. Then we would not install `l10n_XX_reports`. The current workaround is to just not set the `countries` in dependecies but only in the "root" modules. But this requires knowledge of this problem. So it is sometimes not done. So currently we have to do "cleanup" PRs from time to time. Another issue with the workaround is that the `countries` also gives additional metainformation about the module that is lost. E.g. the `countries` info is used to display flag icons for the module in the `Apps` application. task-None
The Open Kiosk button in the self-ordering point of sale dashboard has been separated into its own reusable component. This makes it easier for other modules to customize or extend the button without changing the core dashboard behavior.
Original PR description
To allow overrides in other modules, the “Open Kiosk” button has been extracted into its own widget. 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 change improves how Odoo handles updates to core field properties in the Base module. It supports customization workflows more reliably, including scenarios driven by AI-assisted configuration.
Original PR description
For Customizing AI prompt 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 update clarifies how hierarchy-related search options in Odoo's core data engine are described. It helps developers and implementers better understand these options, reducing confusion when configuring or extending business logic.
Original PR description
task-4280696 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
India company settings now show “Unregistered” as a placeholder when no GST registration type is selected. This helps users understand that an empty value means the company is unregistered, reducing confusion during setup.
Original PR description
As `l10n_in_gst_registration_type` is left empty for unregistered companies, add an `Unregistered` placeholder so users can understand that an empty value means the company is unregistered. This improves the user experience when configuring the GST registration type. Forward-Port-Of: odoo/odoo#288837
The calendar side panel has been reorganized so the activity filter appears as the last item among calendar filters. This makes it easier for users to find after the addition of multiple calendar filters.
Original PR description
Following the introduction of multicalendars (odoo/odoo#261571), the "My Calendars" filters have been added to the calendar sidepanel. The activity filter is now a bit lost in the panel. Moving it as last item of the calendar filters. Task-6573460 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#288527
Spanish electronic invoicing screens are being streamlined so cancellation requests use a single action menu entry instead of separate buttons. The change also makes key JSON files easier to find by keeping SII data with its related document and showing Veri*Factu JSON attachments in document lists.
Original PR description
During the l10n_es [EDI rework](https://www.odoo.com/odoo/project/967/tasks/6175455), the PO introduced some tweaks that would be nice to have. As those tweaks have nothing to do with the rework, we have decided to add them in a different PR: - Replace the direct SII/TicketBAI cancel buttons with a server action bound to the form's action menu, so cancellation goes through a single "Request Cancellation" entry instead of a dedicated button. - Expose the raw JSON attachment on Veri*Factu documents in the list view. - Attach the SII JSON payload to the SII document record itself instead of the invoice, so it travels with the document it belongs to. Here is the edi-rework [PR](https://github.com/odoo/odoo/pull/267440) task-6523345 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The Calendar app now includes a reusable default reminder that can support appointment scheduling. It also replaces a confusing empty attendee label with the clearer wording "Unassigned," making calendar records easier to understand.
Original PR description
This PR adds a calendar.alarm. This one is required as default alarm for the appointment types. To avoid creating a new data file and updating the manifest, this change is not done appointment but in calendar as it can already be useful in that app. To avoid a technical label, this PR replaces the default falsy label of CalendarEvent.partner_ids, which is "Undefined Attendee", by "Unassigned". Enterprise PR: https://github.com/odoo/enterprise/pull/131840 Task-6576867 Forward-Port-Of: odoo/odoo#288801
The calendar event 'Linked to' field now suggests only relevant business records, making it easier for users to choose the right related item. The reference selector also supports searching and filtering, reducing long lists and speeding up selection.
Original PR description
Improve the models suggested in the "Linked to" field on the "calendar.event" model. We should only have business models. Also improving the reference field to use a select menu instead of the regular select element. This allows to search for a model and reduce the selection depending on the search term. Task-6563387 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#287832
The Sales dashboard no longer adds an extra Sales Orders filter when users click the To Deliver or To Invoice cards. This makes the displayed filters match the selected dashboard card more clearly, without changing the orders included in the results.
Original PR description
Steps to produce: --- - Install sales module with demo data. - Go to quotations > Click on `To deliver` or `To invoice` filter. For the `To deliver` and `To invoice` button, the `Sales Orders` filter is redundant. There is no need to have it. Remove the Sales Orders filter when clicking the To Deliver and To Invoice dashboard cards. Both filters already only return confirmed sales orders, making the additional Sales Orders filter redundant. This creates a 1:1 mapping between each dashboard card and its displayed search filter. opw-6574937 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#288744
Users can now open the same quick action menu from the members panel and messaging menu items, not just individual messages. This makes common mail and Discuss actions easier to access and reduces accidental text selection when using long-press on iOS Safari.
Original PR description
Before this PR, we could right-click on messages to show the message actions. This feature was only limited to messages. This PR adds the same feature in member panel and messaging menu item. Also drastically reduces chances for long-press on iOS Safari to trigger accidental text selection. Task-6463002 Forward-Port-Of: odoo/odoo#273806
The AI Agent interface now makes it easier to choose which subagents are allowed to help with a task. This improves clarity for users configuring AI agents and should reduce selection mistakes.
Original PR description
task-[6578342](https://www.odoo.com/odoo/2366/tasks/6578342) Forward-Port-Of: odoo/enterprise#131951
Secondary buttons now keep a consistent border appearance on hover, while disabled buttons use the same style with reduced opacity. Stat buttons also follow the regular secondary hover behavior, giving users a more consistent interface across forms.
Original PR description
The secondary buttons border no longer darkens on hover, and their disabled design now repeats the regular style with an opacity, like the other variants. The stat buttons were forced to the view background color on hover, they now get the regular btn-outline-secondary hover. task-6562366 Forward-Port-Of: odoo/enterprise#131275
Studio users can now choose an end date field when configuring date filters in search views. This helps businesses create more accurate date-range filters, especially for records that span a start and end date.
Original PR description
This commit is the counter part of odoo/odoo#288280 and allows to select an end_date field on date filters in studio. Task-6546268
This update ensures the Wise profile identifier is saved after related Wise connection settings are updated. This helps keep direct deposit configuration consistent and reduces setup issues for U.S. payroll payments.
Original PR description
The wise_profile_identifier is reset after writing on wise_api_key or wise_environment, so assign it after the first 2 values.
Belgian payroll now supports transport reimbursement for each separate home-work trip when JC302 employees or workers have interrupted shifts on the same day. This helps ensure private car and bicycle reimbursements match the actual number of qualifying commutes, while public transport season-ticket handling stays unchanged.
Original PR description
1. Employees and workers under JC302 with interrupted shifts can receive transport reimbursement for each home-work trip, based on separate work entries on the same day. 2. Public-transport season-ticket handling remains unchanged. Task-6532008
Knowledge article editors can now opt in to a whiteboard embedding command from the editor menu. This makes it easier for teams to add visual collaboration content directly into Knowledge articles when needed.
Original PR description
See https://github.com/odoo/odoo/pull/262181 This commit make the knowledge article editor opt-in to the whiteboard embedding powerbox command. task-6102610 Forward-Port-Of: odoo/enterprise#116588
Payroll dashboard warnings now load more efficiently by reducing expensive background processing and making warning actions more flexible. This should improve dashboard responsiveness for payroll teams, especially where many warning checks are displayed.
Original PR description
Prior to this commit, the payroll dashboard could experience high latency during load times. This was primarily caused by the heavy use of `safe_eval` to compute Python-based warning actions…
Prior to this commit, the payroll dashboard could experience high latency during load times. This was primarily caused by the heavy use of `safe_eval` to compute Python-based warning actions (`evaluation_code`), as well as the rigidity of the `button_action` (Many2one) field which limited dynamic UI routing. This commit refactors the warning action system to fix these performance issues and clear technical debt: - Replaced the relational `button_action` field with a generic JSON-driven `action_config` text field on `hr.payroll.warning`. - Migrated all existing data records in `hr_payroll`, `l10n_be_hr_payroll`, and `l10n_be_hr_payroll_account` to use `action_config`. - Converted several Python-evaluated warnings into pure `domain` warnings by moving static dictionary generation and `group_by` clauses into the JSON configuration, allowing the backend to skip `safe_eval` entirely. - Improved the separation of concerns: the backend strictly handles ORM detection (`warning_domain`), while `action_config` handles UI routing. - Set up the infrastructure to support volatile frontend context keys (e.g., for autofocusing fields) without polluting the ORM context.
Odoo now supports Obox features in the Android app, including kiosk mode. This enables businesses using Point of Sale and POS Self Order to run supported Obox workflows on Android devices more smoothly.
The appointment calendar side panel now behaves consistently when editing an appointment type. This removes a visual flicker and prevents activity items from appearing when their filter is not shown, making the experience clearer for users.
Original PR description
Previously the activity filter was removed from the sidepanel when an appointment type was in edition. This introduced a side panel flicker when toggling the edition mode. Also, the activity events were still being displayed in the calendar which doesn't make any sense. Make the activity display consistent with its filter state by removing the "showActivityFilter" override. Task-6573460 Forward-Port-Of: odoo/enterprise#131720
Studio now handles AI options directly on regular fields, so users no longer need a separate AI-field drop action. The update also improves wording and the Studio promotion dialog, making the AI field experience clearer and more consistent.
Original PR description
Forward-Port-Of: odoo/enterprise#131981
Appointment booking screens and emails are clearer and more consistent. Users get better default reminders, more readable appointment cards, improved popover layout, and confirmation emails that greet the right attendee when bookings are made internally.
Original PR description
This commit improves the UI of appointment: * To improve the readability of the "total_capacity_reserved" field in the records of the kanban view, its background color is lightened. * The default…
This commit improves the UI of appointment: * To improve the readability of the "total_capacity_reserved" field in the records of the kanban view, its background color is lightened. * The default alarm of the appointment type is set to 1 day. * The name of the appointment booker is no longer used for the greeting in the confirmation email since it is not set if the appointment is done from the backend. Instead of it, the first of the attendees is used and if they do not exist, the organizer is used. * The popover is improved. Margins are placed between the buttons in the footer, to avoid having them stuck to each other. A maximal width is set for the videocall_location field, this way it does not impact the size of the popover. * To avoid a technical label, the default falsy label of CalendarEvent.resource_ids, which is "Undefined Attendee", is replaced by "Unassigned". Community PR: https://github.com/odoo/odoo/pull/288801 Task-6566639 Forward-Port-Of: odoo/enterprise#131840
Belgian payroll now automatically sets a disabled spouse's fiscal status to "without income" so the correct withholding tax scale is applied. This helps ensure employees with a disabled spouse receive the appropriate tax treatment and reduces manual payroll errors.
Original PR description
When an employee has a disabled spouse, the employee automatically qualifies for withholding tax scale 2 (Bareme II), so the spouse fiscal status must be "without income". If Disabled Spouse is set to True, the spouse fiscal status is now automatically set to "without_income". In Disabled Spouse is not selected, the fiscal status can be manually changed to any other option. task-6542651
The Belgian payroll module now uses the latest officially indexed economic unemployment bonus rates. This helps ensure payslip calculations reflect current legal compensation amounts for affected employees.
Original PR description
Update the economic_unemployment_bonus parameter values to reflect the official rate indexation. task-6541797
Belgian payroll users now get clearer warnings when employees are missing time off allocations, helping HR teams spot and resolve issues before payroll or leave planning is affected. The employee and time off dashboards also make it easier for managers to grant the needed allocations directly from the relevant screens.
Original PR description
mock- https://link.excalidraw.com/l/65VNwvy7c4X/1BoTHSkGUpa - Added new warning on payroll dashboard for employees not having allocation. Doesn't apply to employees without contract and salary…
mock- https://link.excalidraw.com/l/65VNwvy7c4X/1BoTHSkGUpa
- Added new warning on payroll dashboard for employees not having allocation.
Doesn't apply to employees without contract and salary structure dirigeant.
- Added "Not defined" on employee form o-stat-value when there is no allocation.
- Added new button "Grant Time off" on employee Time Off dashboard only visible
to time off managers and when no allocation. On click-> new allocation request
form opens.
- Updated fields for New Allocation request form from Time Off Dasboard:-
- Removed name field.
- Rename "Ask for" to "Duration" for `number_of_day_display` field.
- Change time type field to widget time type tags
- New button "Grant" in place of "Submit Request" directly approves requests.
- Updated the popover form for Time off gantt:
- Warning message on no allocation shows is in alert-danger class.
- If there is no enough allocation then "Allocate & Add" appears which
creates required allocations with leaves.
task-6476239Fixed an issue where online shop and product configurator pages could show an incorrect reference price when a product was sold in a different unit of measure than its base unit. This ensures customers see consistent price-per-unit information, reducing confusion and pricing errors.
Original PR description
Current behavior: On /shop and in the product configurator, the reference price (price per UoM, e.g. $/kg) shown next to a product's price is wrong when the website only sells that product in a uom…
Current behavior: On /shop and in the product configurator, the reference price (price per UoM, e.g. $/kg) shown next to a product's price is wrong when the website only sells that product in a uom other than its base uom. Steps to reproduce: - Enable "Units of Measure" and "Product Reference Price" - Create a product priced per g, with base_unit_count set for kg - Add kg as a packaging and restrict the base uom (g) on the website - Open /shop, or the product configurator, for that product Expected behavior: The reference price matches the "Price Per Unit" shown on the product's own form. Cause of the issue: `_get_sales_prices` and `_get_basic_product_information` divided the price directly by base_unit_count, without converting it from the uom used to compute that price (the main/pricing uom) to the product's base uom. When both differ, the result is off by their ratio. Fix: Convert the price to the base uom before dividing it by base_unit_count, in both the shop listing and the product configurator. opw-6566849 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#288079
The HTML editor now avoids offering heading or paragraph style changes when the change would modify protected form content. This helps preserve website form structure and prevents accidental layout or content corruption while editing descriptions.
Original PR description
If a node is a `p` (or `h1`, ...) and is inside a node marked with `contenteditable=false`, but has `contenteditable=true` itself, the command to change tag (`/h1`, ...) are available and replace the `p` node (thus mutating its parent, which is `contenteditable=false`) This commit modifies the "retagging safe" condition to add the "parent is content editable" next to the existing "the node is removable" task-6573954 (extracted from https://github.com/odoo/odoo/pull/274082) Forward-Port-Of: odoo/odoo#288234
Clicking informational extra text in a many2one field no longer focuses the field or opens the dropdown. This makes it easier for users to select or copy that text without triggering an unwanted menu.
Original PR description
Clicking on the informative extra text of a many2one field would focus the field and open the dropdown, making it inconvenient for the user to simply select or copy the text. This commit prevents the many2one dropdown from opening when the user clicks on the extra lines. Task-6538439 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#289016 Forward-Port-Of: odoo/odoo#288019
The Subscribed Newsletters card now uses its own dedicated illustration instead of reusing the Email Marketing app icon. This makes the portal card grid look more consistent and polished for users.
Original PR description
Before this commit, the Subscribed Newsletters card reused the Email Marketing app icon and was the only non-illustration in the grid. This commit updates the icon to a dedicated illustration. task-6225760 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#288945
Point of Sale online payments no longer include individual customer details in batched transfers. This prevents closing issues when a POS session contains payments from multiple customers, making end-of-day processing more reliable.
Original PR description
We were adding the partner of the payment in a batched transfer, which caused issue with the closing when several partner were involved in the same session. We're now avoiding adding the partner in the batched transfer. Forward-Port-Of: odoo/odoo#289156
This fixes employee counting so staff linked only to portal accounts are not treated as internal employees with users. It improves HR reporting accuracy when portal users were assigned to employee records by mistake.
Original PR description
For employees without user count, we should only consider internal users, so exclude employees where a portal user was assigned by mistake. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#288580
A typo in stock settings validation was corrected so the relevant configuration check works as intended. This helps prevent incorrect validation behavior when users adjust inventory settings.
Original PR description
Forward-Port-Of: odoo/odoo#289150
Opening records with search panel filters linked to archived or restricted items no longer causes a crash. The system now ignores hidden filter groups that users cannot access, improving reliability in affected views such as Social Marketing posts.
Original PR description
Opening a view whose search panel has a `select="multi"` field of type many2many crashes when a record is only linked to comodel records the user cannot see: File "/addons/web/models/models.py", line…
Opening a view whose search panel has a `select="multi"` field of type many2many crashes when a record is only linked to comodel records the user cannot see: File "/addons/web/models/models.py", line 1496, in _search_panel_domain_image id_, display_name = group_id_name(group[field_name]) TypeError: cannot unpack non-iterable bool object Steps to reproduce: - On a db with Social Marketing installed, social accounts are automatically created per website - Open Social Marketing > Posts - Create a new Post with an social account - Open Settings > Social Accounts > the chosen social account - Archive it - Get back to the Post created above => crash `_search_panel_domain_image` restricts the domain with `(field_name, '!=', False)`, which is evaluated on the comodel with sudo and active_test=False, while the group by of the same query joins the comodel through `_search`, which applies record rules and active_test. A record whose values are all archived or hidden by a record rule therefore passes the condition but ends up in a group with no value, which the image loop unpacks as a tuple. This commit skips those groups: their values have no place in the range anyway. Seen on runbot, where `runbot.build.error.trigger_ids` points at `runbot.trigger` records that are archived or restricted by the project group rule. Forward-Port-Of: odoo/odoo#288731 Forward-Port-Of: odoo/odoo#288503
This update fixes the rounded corner styling on side areas of kanban cards in Products and Point of Sale categories. It improves visual consistency so cards look cleaner and more polished across these screens.
Original PR description
*: point_of_sale This commit applies the appropriate border-radius adjustments to the <aside/> elements in the related kanban cards. task-6573555 Requires: -…
*: point_of_sale This commit applies the appropriate border-radius adjustments to the <aside/> elements in the related kanban cards. task-6573555 Requires: - https://github.com/odoo/enterprise/pull/132125 In `pos.category.kanban` | Before | After | |--------|--------| | <img width="385" height="203" alt="Screenshot 2026-09-18 at 11 10 40" src="https://github.com/user-attachments/assets/67537bf4-0aff-4b94-909f-59c7cf60cb96" /> | <img width="389" height="201" alt="Screenshot 2026-09-18 at 11 10 38" src="https://github.com/user-attachments/assets/a9682a97-2fc2-4104-ae5f-794b267273b0" /> | In `Product.template.product.kanban` and `Product Kanban` | Before | After | |--------|--------| | <img width="380" height="102" alt="Screenshot 2026-09-18 at 11 13 59" src="https://github.com/user-attachments/assets/6a437efe-d1fd-483b-9f48-35e625dae5d1" /> | <img width="383" height="102" alt="Screenshot 2026-09-18 at 11 14 05" src="https://github.com/user-attachments/assets/bce0285c-2a06-484a-9592-dfde2a908d0d" /> | --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#289138
This fixes an issue where creating or editing a technical view could fail even when the selected model and view layout were valid. Odoo now applies the chosen model before validating the view layout, preventing false validation errors and making view setup more reliable.
Original PR description
**Problem:** Creating a view from Settings > Technical > User Interface > Views fails with a validation error, even though both the model and the architecture are valid. **Steps to reproduce:** 1. Go…
**Problem:**
Creating a view from Settings > Technical > User Interface > Views fails with a validation error, even though both the model and the architecture are valid.
**Steps to reproduce:**
1. Go to Settings > Technical > User Interface > Views
2. Click New
3. Set the View Name and pick a model in "Model of the view"
4. Set the View Architecture to `<list><field name="name"/></list>`
5. Save
**Current behavior:**
The record cannot be saved:
Error while validating view near:
<list __validate__="1"><field name="name"/></list>
Model not found: False
Duplicating an existing view and editing the copy works, so the issue only shows up on brand new records.
**Expected behavior:**
The view is saved, and validated against the model that was picked.
**Cause of the issue:**
The form edits `model_id`, a non-stored `Many2one` whose inverse `_inverse_compute_model_id` is what actually fills the stored `model` field. The architecture is edited through `arch_base`, whose inverse chain ends in `_inverse_arch` writing `arch_db`; `write` then runs `_check_xml`, which validates the architecture against `view.model`.
Both values therefore reach the record through inverse methods, so the order those run in decides whether `model` is set by the time the architecture is validated. That order became deterministic in this version: the ORM sorts inverse groups by `(field.write_sequence, field index)`. Both fields keep the default `write_sequence` of 0, which leaves the declaration order to break the tie, and `arch` is declared well before `model_id` — so the architecture is validated while `model` is still empty.
The same ordering also breaks a plain edit: changing the model and the architecture of an existing view in a single save validates the new architecture against the previous model.
**Fix:**
`write_sequence` is the ORM's hook for exactly this kind of ordering dependency, so a negative one on `model_id` states the real constraint — the model has to be known before anything is validated against it — rather than leaving it to where the fields happen to sit in the class. It also covers the write path, which a create-only workaround would miss.
opw-6467991
Forward-Port-Of: odoo/odoo#284143This fixes an issue when marking several manufacturing orders as done at the same time. The system now applies completion updates to the correct order, preventing the wrong stock moves from being marked as picked.
Original PR description
The lambda should refer to `p.qty_producing`. Since `button_mark_done` already has a `for production in self:` loop earlier, `production` is filtered, and the lambda evaluates the `qty_producing` of the last MO for all of them. When marking multiple MOs as done, it sets `picked=True` on the wrong moves. Introduced in bb56600bfc81. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#288632
Fixes a Point of Sale issue where opening a company's orders could show a blank screen if one related delivery address had no name. Orders for those unnamed address contacts now display using the parent company name, keeping staff able to review customer orders without interruption.
Original PR description
Steps to reproduce: - Create a company contact with a delivery address that has no name - Make a PoS order for the delivery address and pay it - Open the PoS, open the customer list, and click…
Steps to reproduce: - Create a company contact with a delivery address that has no name - Make a PoS order for the delivery address and pay it - Open the PoS, open the customer list, and click "Orders" on the company Issue: The screen goes blank. Cause: The ticket screen is opened with the company name as search term. The server domain searches on `partner_id.complete_name`, so the orders of the address contact are returned too. They are then fuzzy matched on `getPartnerName()`, which returns `false` for a partner without a name, and `fuzzyLookup` calls a string method on it. The error is raised during rendering, so the whole app is destroyed. Fix: Make `getPartnerName()` always return a string, and fall back on the parent name, like the complete name does. This way the orders of the address contact are still listed when searching on the company name, instead of being filtered out by an empty name. opw-6578541 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#288880
Installing Stock Fleet now correctly enables the required batch transfer setting so its features remain available after changing settings. This prevents the app from being accidentally marked for uninstall when users save configuration changes. Point of Sale stock permissions are also aligned so users can work with batch-related transfers consistently.
Original PR description
Steps to reproduce: - Install stock, stock_fleet - Open the settings - Enable packages (or do any other change) Previously, `stock_fleet` had `stock_picking_batch` as its dependency. However, since the merge of that module into `stock`, we still consider that this group should be enabled to be able to use `stock_fleet`'s features. However, when `stock_fleet` is installed through the apps/-i, the group won't be set, and when opening the settings, since the group isn't set the `onchange` triggers to set the `module_stock_fleet` to False, prompting its uninstall when saving the settings. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#288352
Administrators can now view and create API keys for other users, making it easier to manage automated or bot accounts that rely on API keys instead of passwords. This helps teams centrally maintain script and integration access without logging in as each user.
Original PR description
This make it possible for an admin to list and also create API keys for other users. This is useful to manage "bot" users, i.e. accounts with no password that are only used with API keys in scripts.
Fixed an error that could prevent users from duplicating rental products when pricing rules were attached to a variant without variant-defining attributes. This keeps product setup workflows reliable and avoids interruptions when copying products such as rental listings.
Original PR description
Issue: Duplicating a product raises `ValueError: False is not in list` when the product has a pricelist rule set on its variant and that variant holds no attribute value. Steps to reproduce: 1.…
Issue: Duplicating a product raises `ValueError: False is not in list` when the product has a pricelist rule set on its variant and that variant holds no attribute value. Steps to reproduce: 1. Install `website_sale_renting` with the demo data. 2. Open the `Luxury Room` product, whose only attribute, `Breakfast`, doesn't create variants, and which has a pricelist rule set on its variant. 3. Duplicate it. Cause: `get_combination_key` builds the combination of a variant through `product_template_variant_value_ids.mapped(...)`. On an empty recordset, `mapped` calls the given function once with that empty recordset instead of not calling it at all, so `attribute_line_id.id` is `False` and `attribute_line_ids.index()` raises. A variant holds no attribute value when its template has no attribute line, or only lines whose attribute doesn't create variants. Fix: Iterate `product_template_variant_value_ids` instead of mapping over it, so that a variant without attribute value gets an empty combination key. Version:20 (bugfix) Forward-Port-Of: odoo/odoo#288252
This fixes a display issue where time off allocation warnings could show the remaining balance using the request's unit instead of the time off type's unit. Business users now see consistent and accurate remaining time information when allocations and requests use different units.
Original PR description
When the unit of measure of a time off type doesn't match the unit of a request -approved and based on an allocation-, the time remaining on the allocation incorrectly holds the unit of the request rather than the time-off type. It thus displays inconsistent information. The dependency of the computation is now set to `work_entry_type_id.unit_of_measure` rather than `work_entry_type_request_unit` to correctly reflect the remaining duration of the allocated time. task-id: 6545527
Invoices that have already been sent through PEPPOL can no longer be selected for sending again. This prevents accidental duplicate sends and makes the interface clearer by showing why the option is unavailable.
Original PR description
If the invoice is already sent through PEPPOL, the checkbox for sending the invoice should then be readonly and unchecked. Currently is correctly unchecked but not readonly. We fix it by copying what French localization (`l10n_fr_pdp`) does already, giving a reason for disabling. <img width="1359" height="948" alt="immagine" src="https://github.com/user-attachments/assets/6f91ab34-8989-487e-8cd9-96dafee7bcb5" /> . Pad: https://pad.odoo.com/p/accountingv20 pad-accountingv20 Forward-Port-Of: odoo/odoo#288898
Fixed an issue where manufactured lot-tracked products could be placed in the default stock location after components were unreserved and re-reserved. Putaway rules are now applied after production, helping ensure finished goods are stored in their intended warehouse locations.
Original PR description
Currently, when the user re-reserves a component and produces an MO for a lot-tracked product, putaway rules stop working. ## Steps to produce: - Install the Manufacturing application. - Go to…
Currently, when the user re-reserves a component and produces an MO for a lot-tracked product, putaway rules stop working. ## Steps to produce: - Install the Manufacturing application. - Go to Settings and enable Lots & Serial Numbers and Storage Locations. - Create a product named 'Laptop' and set it to be tracked by Lots. - Create a product named 'Graphics card' with some quantity on hand. - Create a Bill of Materials (BoM) for the Laptop with Graphics card as a component. - Create a location named 'Laptop Shelf' with 'WH/Stock' as its parent location. - Create a putaway rule: - When a product arrives in: WH/Stock - Product: Laptop - Store to: WH/Stock/Laptop Shelf - Create and confirm a Manufacturing Order (MO) for the Laptop. - Unreserve the components, open Details, and re-add the Graphics card. - Click Produce All and check the on-hand quantity list view of the Laptop. ## Issue: The Laptop is stored in WH/Stock instead of WH/Stock/Laptop Shelf. ## Root cause: When the user presses the unreserve button the finished move is passed to `_do_unreserve` https://github.com/odoo/odoo/blob/157874aad3aebef5bc9268de6e17530641107e31/addons/mrp/models/mrp_production.py#L2407 which unlinks all the move lines on finished product moves if they are not picked: https://github.com/odoo/odoo/blob/157874aad3aebef5bc9268de6e17530641107e31/addons/stock/models/stock_move.py#L1043 Now when the user presses the Produce All button, `button_mark_done` is called, which calls `_post_inventory` at: https://github.com/odoo/odoo/blob/a51ca77c825d2dba326dd540e2b4c04ef6c2385d/addons/mrp/models/mrp_production.py#L2236 `_post_inventory` assigns `lot_ids` to the finished product moves at: https://github.com/odoo/odoo/blob/157874aad3aebef5bc9268de6e17530641107e31/addons/mrp/models/mrp_production.py#L1928-L1930 This calls `_set_lot_ids` which creates a move line with quantity 1 at: https://github.com/odoo/odoo/blob/157874aad3aebef5bc9268de6e17530641107e31/addons/stock/models/stock_move.py#L679-L683 After that, `_post_inventory` sets the quantity for the finished product moves at: https://github.com/odoo/odoo/blob/157874aad3aebef5bc9268de6e17530641107e31/addons/mrp/models/mrp_production.py#L1935 Which calls `_set_quantity` and the delta quantity is now zero at: https://github.com/odoo/odoo/blob/157874aad3aebef5bc9268de6e17530641107e31/addons/stock/models/stock_move.py#L477-L483 Because `_set_lot_ids` has already created a move line that satisfies the move quantity, `_process_increase` is not called. Since `_process_increase` is not called, `_set_quantity_done` is never called at: https://github.com/odoo/odoo/blob/157874aad3aebef5bc9268de6e17530641107e31/addons/stock/models/stock_move.py#L463-L465 Since `_set_quantity_done` is not called, `_apply_putaway_strategy` is never called within that function at: https://github.com/odoo/odoo/blob/157874aad3aebef5bc9268de6e17530641107e31/addons/stock/models/stock_move.py#L2565 As a result, the laptop ends up in stock instead of on the shelf. This issue did not occur in lower versions because the feature to produce multiple lots was introduced in version 19.0 by the following commit: https://github.com/odoo/odoo/commit/4bb4e08066449177f89382718ceadd840ce90d0e Before this commit, only `_set_quantity` was called. Since no move line was created because lot_ids were not set in `_post_inventory`, `_process_increase` was called, which then called `_apply_putaway_strategy`, so the putaway rules were applied correctly. ## Solution: Apply putaway rules in the post-inventory function after the user manufactures a product, ensuring the items are placed in the correct locations and preventing products from being misplaced even when putaway rules are defined. opw-6517324 Forward-Port-Of: odoo/odoo#288739 Forward-Port-Of: odoo/odoo#287390
This fixes a crash that could occur when users fetched the processing status of Romanian e-Factura documents from SPV. It ensures signature files are saved correctly, allowing businesses to continue invoice status checks without interruption.
Original PR description
Steps to reproduce: - Send an invoice to the SPV (Romanian e-Factura). - Once the SPV finished processing it, click "Fetch Status" on the e-Factura document. - Odoo crashes with binascii.Error:…
Steps to reproduce: - Send an invoice to the SPV (Romanian e-Factura). - Once the SPV finished processing it, click "Fetch Status" on the e-Factura document. - Odoo crashes with binascii.Error: Incorrect padding Cause of the issue: _request_ciusro_download_answer extracts the signature file from the SPV zip answer and re-serializes it with etree.tostring(...), which gives plain XML bytes, not base64 But _l10n_ro_edi_fetch_invoice_sent_documents and the 3 other callers that persist that signature still ran it through base64.b64decode() before wrapping it in BinaryBytes (which already expects raw bytes, not base64). Decoding real XML as base64 only "works" by accident when the XML happens to contain a number of base64-alphabet characters that's a multiple of 4 after the invalid ones get silently stripped - otherwise it blows up with "Incorrect padding". This got introduced by 41fe2ebdb9cc (fields.Binary return BinaryValue), which flipped a base64.b64encode() call to base64.b64decode() at these 4 spots instead of just dropping the base64 call entirely. A previous fix (0750ee145ae2) already fixed the sibling issue on the invoice's own attachment_raw but missed these. Solution: Drop the erroneous base64.b64decode around the signature's attachment_raw at the 4 call sites, and fix the tests that were mocking attachment_raw as base64-encoded instead of raw bytes opw-6562123 Forward-Port-Of: odoo/odoo#288140
Fixed an issue in the API documentation where opening a related field link in a new tab could show the original model instead of the related model. This makes navigation in developer documentation more reliable and avoids confusion when reviewing model relationships.
Original PR description
Steps to reproduce: * open api_doc * select a model (eg: project.task) * middle click on a many2one field (eg: stage_id) Observed behavior: The new tab is opened on the base model (project.task) instead of the comodel (project.task.type). This commit fixes the issue by using `t-att-href` to point to the correct model and `preventDefault` to avoid a full reload when clicking on a m2o. Forward-Port-Of: odoo/odoo#288558
Sales order previews and reports now show the correct section quantity, unit of measure, and unit price. This prevents customers and sales teams from seeing misleading quantities or pricing, especially on mobile previews and sections with hidden composition.
Original PR description
The section quantity and pricing displayed in the sale order preview and report are inconsistent in some cases. After https://github.com/odoo/odoo/commit/34c47e5493bc36af338efbb54050e060b04f8ea3, the section quantity and UoM are dynamically displayed in the preview, but the mobile preview still shows the static `1 Units`. Additionally, when a section has `hide_composition` enabled, the unit price is incorrectly displayed as the section's total price instead of being based on the section quantity. This PR fixes both issues by: - Displaying the dynamic section quantity and UoM in the mobile preview. - Computing the section unit price from its total price and quantity when the composition is hidden. Forward-Port-Of: odoo/odoo#288743
Long-pressing an order line in Point of Sale no longer resets a manually adjusted price back to the product's default price. This helps cashiers keep intended pricing changes intact when interacting with existing order lines.
Original PR description
Long-pressing an order line recomputed its price and reset it to the product's original price. Preserve the existing price when the product is neither configurable nor part of a combo. --- Task: https://www.odoo.com/odoo/project/1737/tasks/6570304 Forward-Port-Of: odoo/odoo#288053
This fixes a small internal issue where a broken message format caused the wrong kind of error during export identifier checks. The change helps developers and support teams see the intended validation error, making troubleshooting clearer without changing normal user workflows.
Original PR description
The format was broken. `'{}:{}' % it` → `TypeError` instead of `AssertionError`.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#288836
Forward-Port-Of: odoo/odoo#288610Changing the pricelist on a saved quotation now correctly updates prices for combo product items. This prevents quotes from showing outdated combo item prices and helps ensure customers receive pricing that matches the selected pricelist.
Original PR description
Versions -------- - 20 Steps ----- 1. Create and save a quotation with a combo product; 2. change the pricelist for one giving a different price on that combo product. Issue ----- The combo item…
Versions -------- - 20 Steps ----- 1. Create and save a quotation with a combo product; 2. change the pricelist for one giving a different price on that combo product. Issue ----- The combo item lines keep the prices given by the previous pricelist. Cause ----- Commit e78f729d removed the `Update Prices` button and moved `_recompute_prices` to the `pricelist_id` onchange. The lines are therefore in memory records now, whereas they were stored ones when the recompute was triggered by the button. `_get_combo_item_display_price` prorates the price of the combo product, computed on the line returned by `_get_linked_line`. As of commit f1e68cc, that method returns `linked_line_id` whenever it is set, i.e. the stored line, whose `order_id` is the stored order, hence still the previous pricelist. Solution -------- When the line is an in memory record, look its linked line up among the order lines, by origin, so that the in memory version is returned. opw-testing-day-v20 Forward-Port-Of: odoo/odoo#288543
This fix prevents users from accidentally triggering repeated delete requests for the same email or chat attachment when clicking quickly or using a slow connection. It avoids unnecessary error messages and keeps the attachment removal experience smoother in Discuss and messaging flows.
Original PR description
**Steps to reproduce:** - Open Discuss app - Open any conversation - Setup the browser with throttled connection (e.g. Slow 4G) - Select multiple files to attach but don't send the message - While…
**Steps to reproduce:**
- Open Discuss app
- Open any conversation
- Setup the browser with throttled connection (e.g. Slow 4G)
- Select multiple files to attach but don't send the message
- While some are loading, double click the delete button of one of the loaded attachment preview
- Traceback will appear: `404 Not Found`
**Issue:**
On click the delete button triggers a deletion request on `/mail/attachment/delete`.
Repeatedly clicking the delete button before the first request was completed (and the `AttachmentList` get updated) but after the attachment was deleted, will cause a `404 Not Found` due to the `raise NotFound()` which was added by [1] in `mail_attachment_delete`.
```py
attachment = request.env["ir.attachment"].browse(int(attachment_id)).exists()
if not attachment or not attachment._has_attachments_ownership([access_token]):
request.env.user._bus_send("ir.attachment/delete", {"id": attachment_id})
raise NotFound()
```
**Fix:**
Prevent concurrent deletion requests for the same attachment by keeping track of attachments currently being deleted.
[1] https://github.com/odoo/odoo/commit/50f45dd436b97027cb1461410efeee7057dad4e8#
opw-6499125
Forward-Port-Of: odoo/odoo#288884
Forward-Port-Of: odoo/odoo#285060Changing an employee's working schedule no longer shifts the dates on existing time off requests for employees in certain time zones. The request dates remain unchanged while the system still recalculates the time off duration based on the new schedule.
Original PR description
## Description Changing an employee version's working schedule recomputes the internal dates of subsequent time off requests. The `hr.leave` write override then mirrors these recomputed UTC values…
## Description Changing an employee version's working schedule recomputes the internal dates of subsequent time off requests. The `hr.leave` write override then mirrors these recomputed UTC values back to the request dates. For timezones ahead of UTC, midnight on a non-working day can therefore shift the requested date to the previous day. This fix marks the schedule-triggered re-computation as an internal fast update, ensuring that the dates selected on the time off request remain the source of truth while still allowing the leave duration to be recomputed according to the new working schedule. Regression coverage is added to ensure that changing an employee's working schedule: * preserves the dates selected on existing time off requests; * correctly recomputes the leave duration according to the new schedule. ## Steps to reproduce 1. Create an employee with timezone Europe/Brussels and a Monday–Friday working schedule. Before creating any leave, set the employment record’s effective date and contract start date to 3 March 2025. 2. Create a full-day time off request from 23 to 26 February 2026. Its duration is initially four working days. 3. Change only the employee’s working schedule to a duration-based Tuesday–Friday schedule, with 7.6 hours per working day and Monday off. Leave the effective date and contract dates unchanged, then save. **Before the fix:** the request’s start date incorrectly shifts to 22 February. **After the fix:** the dates remain 23–26 February, while the duration correctly decreases to three working days. opw-6456107 Forward-Port-Of: odoo/odoo#281385
The email plugin can now keep users signed in for longer, with a default token duration of seven days. Administrators can adjust this duration through a system setting, reducing the need for daily logins while keeping access limited to the Outlook plugin endpoints.
Original PR description
Purpose ======= Allow customizing the expiration time of tokens, so users don't need to login everyday in the plugin. This is customized with a system parameter, with a default of 7 days. Those tokens are limited to endpoints `auth="outlook"`. Task-6466253 Forward-Port-Of: odoo/odoo#288572 Forward-Port-Of: odoo/odoo#287767
Delivery slips now show the name of an outer package clearly when one package is placed inside another. This makes shipping documents easier to read and helps warehouse and delivery teams identify packaging details without confusion.
Original PR description
Before this PR:- ================= When a pack is put inside another pack, the delivery slip displays the outer pack, but its name is unreadable. <img width="975" height="300" alt="image" src="https://github.com/user-attachments/assets/abaf0c1c-1fb7-449a-87d4-ec7ed6988f88" /> After this PR:- ================= Make the outer pack name readable on the delivery slip. <img width="983" height="312" alt="image" src="https://github.com/user-attachments/assets/a271c27d-da3c-4a3d-b56a-8a860886f895" /> Enterprise PR:- odoo/enterprise#131741 Forward-Port-Of: odoo/odoo#288498
Connecting bank synchronization no longer removes payment options that users previously configured on bank journals. This preserves existing incoming and outgoing payment settings while still adding any missing default options, reducing reconfiguration work after syncing a bank account.
Original PR description
**Steps to reproduce:** - Install Accounting - Configure "Bank" journal: * Add several incoming payments * Add several outgoing payments - From Accounting dashboard, connect Bank (e.g. Odoo Bank Sync Demo) **Issue:** After bank sync, all the incoming/outgoing payments added on the Bank journal are removed. Only the default ones are re-created. **Solution:** Keep all the existing incoming/outgoing payments (i.e. payment method lines) and only create the default ones for the payment method types that don't exist. opw-6424407 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281658
Sale orders now show the correct line number when a product line is added after a section. This prevents confusing or duplicated numbering in sales documents, helping users review order lines more reliably.
Original PR description
Steps to reproduce: 1. Open a sale order. 2. Add a section. 3. Add a line after the section. Issue: The line number of the line after the section is incorrect. Cause: The line number counter is incremented twice for section lines. Fix: Increment the counter on the order line itself instead of the pseudo-elements, ensuring the counter is incremented only once per line. Forward-Port-Of: odoo/odoo#288491
Warehouse transfers can now be automatically placed into a batch even when the batch limit is set to one. This fixes a configuration where automatic batching was enabled but no batch was created, helping teams rely on consistent warehouse processing rules.
Original PR description
Issue Before This Commit: ======================== When automatic batch creation is enabled and the maximum number of pickings per batch (batch_max_pickings) is set to 1, no batch is created for the picking. Steps to Reproduce: ========================= 1: Install the stock module. 2: Enable automatic batch creation. 3: Set the maximum number of pickings to 1 and enable Group by Contact on an operation type. 4: Create a transfer for that operation type. 5: Observe that no batch is created for the picking. Cause of the issue: ========================= In _is_auto_batchable, the condition returns False when batch_max_pickings is set to 1, preventing the picking from being automatically batched. After This Commit: ======================== Update _is_auto_batchable to allow automatic batching when batch_max_pickings is specified and is greater than or equal to 1. Forward-Port-Of: odoo/odoo#288295
The Attendance app calendar now greys out holidays and other unavailable days, making it easier for users to understand attendance context at a glance. This aligns the calendar experience with the Time Off app and reduces confusion when reviewing schedules.
Original PR description
The calendar view on Attendance app should look similar to the one on Time Off app, with holidays greyed out. task-6576916 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 update prevents users from being sent back to the login screen after signing in while a websocket-based service such as live chat is active. It ensures the existing session is saved without overwriting the newly logged-in session in the browser, improving login reliability.
Original PR description
Before this commit, signing in from a page holding a websocket connection could land the user back on the login form. This happens because the websocket handshake marks the session dirty to get it written on disk, and _save_session sends a "session_id" cookie back for every dirty session. A handshake answered between the login response and the request that follows it therefore puts the pre-login session back in the browser. Note that the failure was seen on master, where a livechat tour signs in with the bus connected, but every version since 17.0 answers the handshake the same way. This commit saves the session from the handshake itself, so that the response carries no session cookie. https://runbot.odoo.com/odoo/error/947173 Forward-Port-Of: odoo/odoo#288667 Forward-Port-Of: odoo/odoo#287960
This update fixes cases where Odoo could silently use desktop-style behavior on small screens or hide debug-only interface elements because outdated internal flags were still being read. It also adds stronger checks so similar mistakes are caught during testing instead of reaching users.
Original PR description
Removes depracated `env.isSmall` and `env.debug` and make it throw if used (to prevent forward port mistakes) Enterprise PR: https://github.com/odoo/enterprise/pull/130698 Forward-Port-Of: odoo/odoo#288843
Users who leave a Discuss call themselves will no longer see a misleading message saying the server disconnected them. This reduces confusion while still warning users when a call really ends unexpectedly from the server side.
Original PR description
Before this commit, manually leaving a Discuss call showed the warning meant for a server-initiated disconnection. Steps to reproduce: 1. Join a call in a Discuss channel. 2. Click Disconnect. 3. Observe "Disconnected from the call by the server". This happened because the server ended the RTC session and the session/ended bus notification reached the browser before the leave_call RPC response, while the local session was still active. This commit fixes the issue by marking the RTC service as leaving for the duration of the RPC and ignoring the corresponding local-session deletion. Unexpected server-side session endings still show the warning. <img width="499" height="175" alt="Screenshot 2026-09-11 at 01 14 46" src="https://github.com/user-attachments/assets/f3cfbfb3-5c25-4139-9a0a-1a558399d73f" /> Forward-Port-Of: odoo/odoo#287754
Equity contact cards now use the standard card width instead of a custom narrow layout. This prevents cards from being squeezed on medium-sized screens, making titles and key information easier to read.
Original PR description
Before this commit, the cards forced --KanbanRecord-width to 18vw, squashing them on medium screens (+ titles often truncated) This commit drops the override for default width, and swaps the hardcoded padding and graph margins for the --Card-padding-* variables they were mirroring by hand. | Current | This commit | |--------|--------| | <img width="1064" height="485" alt="image" src="https://github.com/user-attachments/assets/a8631b23-c231-45e7-8b83-da74e0081a42" /> | <img width="1064" height="485" alt="image" src="https://github.com/user-attachments/assets/43d469e9-f889-4e59-a4c1-173863706d69" /> | task-6578400 Forward-Port-Of: odoo/enterprise#131908
The marketing automation setting that controls global reply cancellation is now stored at the campaign level instead of on individual activities. This better matches how campaigns are managed and prepares the system for upcoming related functionality without changing day-to-day user workflows.
Original PR description
Currently, global reply cancel option is stored at activity level. However it makes more sense at campaign level. This commit adds relevant field on campaign model *à l'arrache* due to opportunity window to change DB scheme in stable. Feature is coming soonish. Forward-Port-Of: odoo/enterprise#132011
When helpdesk tickets are merged, related timesheets now use the same sales order item as the merged destination ticket. This prevents inconsistent billing or service tracking information after tickets with different sales items are combined.
Original PR description
Currently when you merge helpdesk tickets with differing sale order items, the sales order item listed on the timesheets of the source ticket is not updated to match the destination ticket's sales order item. This PR ensures uniformity bugfix-6473396 Forward-Port-Of: odoo/enterprise#131155 Forward-Port-Of: odoo/enterprise#129060
This fix adjusts the rounded corners and spacing on kanban cards in AI Agents, Referrals, and ESG database configuration views. The change makes cards display more consistently and avoids visual issues when side panels appear on either side of a card.
Original PR description
*: hr_referral, esg This PR applies the appropriate border-radius adjustments to the <aside/> elements in the related kanban cards. About ESG, the default Kanban card only supports an aside on the…
*: hr_referral, esg This PR applies the appropriate border-radius adjustments to the <aside/> elements in the related kanban cards. About ESG, the default Kanban card only supports an aside on the left. However, in the Database Kanban view, the aside is positioned on the right, which causes issues with the card border radius and margins. This PR adds module-specific customizations to handle this case. task-6573555 Requires: - https://github.com/odoo/odoo/pull/289138 In `ai.agent.kanban` | Before | After | |--------|--------| | <img width="389" height="220" alt="Screenshot 2026-09-18 at 11 17 22" src="https://github.com/user-attachments/assets/f887d40e-8b61-498f-9f24-dd6601721993" /> | <img width="387" height="222" alt="Screenshot 2026-09-18 at 11 17 28" src="https://github.com/user-attachments/assets/f013f743-a249-40de-9d85-6e78ce626f28" /> | In `hr.referral.reward.employee.referral.backend.kanban` | Before | After | |--------|--------| | <img width="386" height="136" alt="Screenshot 2026-09-18 at 11 19 36" src="https://github.com/user-attachments/assets/e853a646-1288-4c1a-806e-147edc9774f0" /> | <img width="384" height="129" alt="Screenshot 2026-09-18 at 11 19 25" src="https://github.com/user-attachments/assets/cc4f0137-e402-4486-8f5a-7af54ca8fd99" /> | In `hr.referral.reward.employee.referral.backend.kanban` | Before | After | |--------|--------| | <img width="386" height="136" alt="Screenshot 2026-09-18 at 11 19 36" src="https://github.com/user-attachments/assets/e853a646-1288-4c1a-806e-147edc9774f0" /> | <img width="384" height="129" alt="Screenshot 2026-09-18 at 11 19 25" src="https://github.com/user-attachments/assets/cc4f0137-e402-4486-8f5a-7af54ca8fd99" /> | In ESG/Configuration/Databases | Before | After | |--------|--------| | <img width="386" height="167" alt="Screenshot 2026-09-18 at 11 20 57" src="https://github.com/user-attachments/assets/acfe0958-95ae-4e80-903e-8590a1804a06" /> | <img width="390" height="180" alt="Screenshot 2026-09-18 at 11 21 00" src="https://github.com/user-attachments/assets/a2c33ec5-84e8-4119-8625-f8411a7b609a" /> | Forward-Port-Of: odoo/enterprise#132125
Payslip corrections now use the appropriate accounting dates for both the refund and the corrected payslip. This helps payroll and accounting records reflect the correct timing, reducing confusion during financial reconciliation.
Original PR description
-The refund payslip's accounting date is set to the day of the correction (since it's put as paid directly). -The accounting date of the correction payslip us set to the day of its validation Forward-Port-Of: odoo/enterprise#131902
Asset depreciation models based on rates are now named by the time it takes to fully depreciate an asset, making them easier to understand. The change also fixes translated labels by removing an English-only plural ending that could break names in other languages.
Original PR description
This commit does 2 things: 1. Rate-based models were named after their rate, e.g. "2.78% per Month". Now they are named after the duration it takes to fully depreciate the asset. For example "2.78% per Month" now reads "36 Month". A helper function was added to handle the rounding of the method number. 2. Also the plural 's' that was appended to the duration was removed. It was added onto the end of the translated period label, so it produced broken names in every language other than English. task-6498452 Forward-Port-Of: odoo/enterprise#129366
This fixes an intermittent automated check that sometimes clicked the wrong navigation link before an accounting report had fully opened. The change makes the test wait for the report to load first, improving reliability of quality checks without changing user-facing behavior.
Original PR description
The issue appeared 1 every 3 run, the reason was because it didn't wait the report to be opened and clicked on the breadcrumb. So it clicked the breadcrumb of the return and not the one of the report. The fix is to add a step in between checking the report is loaded. Runbot error: https://runbot.odoo.com/odoo/error/944180 Forward-Port-Of: odoo/enterprise#130961 Forward-Port-Of: odoo/enterprise#130807
Payslips now calculate attendance-based work entries using paid working time only, excluding any recorded unpaid break duration. This prevents employees from being paid for break time when attendance records include unpaid breaks.
Original PR description
Steps to Reproduce: 1. Create an attendance from 8AM to 4PM (8 hours) 2. Add 2h of Break Duration -> This reduces the worked time from 8h down to 6h. 3. Generate a payslip for this employee -> 8H of attendance is included, but it should be 6H instead Fix: Exclude `attendance.break_duration` -if there is one set- from attendance work entries' total value. task-6573873
The Canadian Balance Sheet now displays correctly when using the horizontal split view. Assets are separated from equity and liabilities as intended, making the report easier to read and reducing confusion for Canadian accounting users.
Original PR description
The Canadian Balance Sheet "split horizontally" feature was broken during the refactor [1]. This commit - fixes the correct split between the Assets on the right and the Equity and Liabilities on the left, - remove the redundant split=right on child of aforementioned category. [1]: https://github.com/odoo/enterprise/pull/114127 task-none (DSH finding) **before** <img width="1903" height="861" alt="image" src="https://github.com/user-attachments/assets/58ee1ab8-5ca4-4d80-9567-5588d70b3f64" /> **after** <img width="1916" height="881" alt="image" src="https://github.com/user-attachments/assets/894358cd-d18a-4039-a468-65c7cabb20cf" /> Forward-Port-Of: odoo/enterprise#131933
Blog imports now correctly handle multiple blogs with the same name by tracking them with their original external identifiers. This prevents posts from being linked to the wrong blog or failing to match during website generation.
Original PR description
Blogs with the same name was creating a conflict in the mapping of id to created odoo blog, which meant that the blog post matching with the blog itself was failing. This fix introduces external ids for the blogs which is the id of the foreign website, making it much easier to keep track of the mapping between the external records and the created odoo records.
This fixes an issue in Odoo Studio where removing an element could leave nearby text behind in the generated customization. Users now get cleaner, more accurate layout changes when editing views that mix text and elements.
Original PR description
Have an arch like ``` <div> <br /> TEXT <span /> </div> ``` Now remove the block `TEXT <span />` Before this commit, the resulting inheriting arch was just `<xpath expr="//span" position="replace" />` So the `TEXT` was not removed After this commit, the `TEXT` is removed along with the following span opw-6524957 Forward-Port-Of: odoo/enterprise#131812 Forward-Port-Of: odoo/enterprise#131717
Creating an appointment from the calendar now keeps the exact time slot selected by the user. This prevents bookings from being resized to the default appointment duration, improving scheduling accuracy.
Original PR description
When creating an event from the calendar view of an appointment type, the duration of the event was set to the duration of the appointment, therefore bypassing the slot we drew. This commit fixes this behavior by giving the priority to the end date of the drawed slot. Task-6412432 Forward-Port-Of: odoo/enterprise#130171
This fix ensures AI-generated pivot reports correctly understand grouped date or interval columns. It prevents report display issues by converting the AI response into the format expected by the reporting view.
Original PR description
The AI backend returns column groupbys as a list containing both strings and dictionaries with interval information. While this format is used to preserve the interval metadata, the pivot model expects `colGroupBys` to be a flat list of strings. This commit updates the view patch to flatten dictionary entries into their corresponding `<field>:<interval>` strings before assigning them to the pivot model metadata, ensuring the format matches the pivot model's expectations. task-6377810 Forward-Port-Of: odoo/enterprise#129515
The automated test for rental product availability now uses the same rental dates when comparing reserved stock with what appears on the product page. This prevents misleading test failures and helps keep online stock availability checks reliable.
Original PR description
`test_website_availability_while_continuing_selling` ensures the display of units left on product page is coherent with the stock available. For this, the test creates a rental order with default dates based on now. This fix ensures the same dates are used on the product page so that we compute the quantity left on the same dates. Failing since PR: https://github.com/odoo/enterprise/pull/106988 runbot-241108 Forward-Port-Of: odoo/enterprise#131763
This fix prevents Belgian salary contract setup data from being accidentally removed when optional linked fields are deleted. It also moves a holiday-related record to the correct Belgian salary contract module, helping payroll and salary package data load reliably.
Original PR description
res_field_id was set as ondelete='cascade', deleting record and causing the error "Cannot update missing record". res_field_id being optional, it also did not make sense to have it ondelete="cascade". For the same reason, cost_res_field_id was also corrected. double_holiday record not required in data for l10n_be_hr_payroll but required in l10n_be_hr_contract_salary. task-6254030
This fixes several AI chat issues so users can again show agent steps, see accurate tool activity status, and get clearer chat names after the first message. It also aligns AI agent name styling with other chat participants for a more consistent experience.
Original PR description
Purpose: --------- #### Show agents steps toggler in composer actions The option to toggle the agents steps is missing in the composer actions. There were 2 ways of adding composer actions for AI…
Purpose: --------- #### Show agents steps toggler in composer actions The option to toggle the agents steps is missing in the composer actions. There were 2 ways of adding composer actions for AI chats (probably after resolving conflicts). #### Update tool status when tools are called The tool status in ai chats is not updated anymore when tools are called. This happens because `_store_session_fields` is called when the tool results are sent to the LLM since commit [1] Therefore, we are sending the tool status which is immediately overridden by this call to `_store_session_fields`. This commit fixes it by removing the direct updates, and let `_store_session_fields` handle this case as well. This PR also changes the font-weight of the agent header in ai chats to match the one of the other users #### Always rename ai chats on first message Since commit 1, AI chats created with a channel title are not renamed anymore. This commit restores the previous logic, which is to always rename AI chats on the first message (to make it easier to find them in the chat history). [1] a7523d2e84edb258f42141b3154493a8a8e12e58 Forward-Port-Of: odoo/enterprise#131681
Asset depreciation is now calculated using exact monthly portions when periods cover full months or years. This avoids small day-count differences, helping accounting results align more consistently with expected depreciation schedules.
Original PR description
Old behavior: Linear depreciation for constant periods used a day-based ratio (days_passed / total_days). New behavior: When evaluating full periods (exact months or years), the engine now bypasses day-based logic and uses strict monthly fractions: Depreciable_Value * (Period_Months / Total_Months).
This fixes Argentina electronic export invoices so small-quantity lines are reported with the correct decimal precision instead of being rounded to two decimals. It prevents ARCA rejections that could block affected companies from issuing export invoices after upgrading.
Original PR description
### Problem `l10n_ar_edi` reports WSFEX / WSBFE line quantities (`Pro_qty`) truncated to 2 decimals in 19.0, no matter what precision the database has configured. `_get_line_details()` reads the…
### Problem
`l10n_ar_edi` reports WSFEX / WSBFE line quantities (`Pro_qty`) truncated to 2 decimals in 19.0, no matter what precision the database has configured.
`_get_line_details()` reads the precision like this:
```python
uom_precision_digits = min(self.env['decimal.precision'].precision_get('Product Unit of Measure'), 2)
```
In 19.0 that `decimal.precision` record was renamed to **`Product Unit`** (`uom/data/uom_data.xml`, `decimal_product_uom`), so the lookup matches no record. `precision_get` does not raise in that case, it falls back to a default of 2 (`base/models/decimal_precision.py`: `return res[0] if res else 2`), so `min(2, 2) = 2`.
The rename was applied everywhere else — `account.move.line.quantity` already declares `digits='Product Unit'`. Only this lookup kept the old name.
### Impact
A quantity of `0.042` is sent as `0.04`. ARCA rejects the invoice with **error 1815** (item math inconsistency: `unit price x quantity - discount` no longer matches the item total), which blocks export invoicing completely.
It only shows up after upgrading to 19.0: on 18.0 the record still had the old name, so the lookup worked and the configured precision was used.
On our hosted fleet we identified **67 Argentinian databases** that use WSFEX or WSBFE and have a unit precision above 2. Eight of them already run 19.0 and are affected today; the rest will hit the same rejection as they upgrade.
### Fix
Use the current record name, and raise the cap to **6**, the maximum `Pro_qty` accepts according to the WSFEX developer manual ([V3.1.1](https://www.afip.gob.ar/ws/documentacion/manuales/WSFEX-Manualparaeldesarrollador_V3.1.1_ARCA.pdf), p. 15).
### Test plan
`l10n_ar_edi/tests/test_fex.py` adds `test_ar_edi_wsfex_pro_qty_decimal_precision`, covering three cases:
| `Product Unit` | quantity | expected `Pro_qty` |
|---|---|---|
| 3 | 0.042 | `0.042` |
| 2 | 0.042 | `0.04` |
| 8 | 0.1234567 | `0.123457` (capped at 6) |
It does not go through the ARCA mock: it calls `_get_rounded_base_and_tax_lines()` and `_get_line_details()` directly.
### Note
Supersedes #130582 by the same author, which carried the same one-line fix without a test. Please review this one instead.
### Left out on purpose
`price_precision_digits` in the same method caps the unit price at 3 digits, which does not come from the specification either. That lookup still uses a record name that exists (`Product Price`), so there is no regression, and we have no rejection reported because of it. Changing it would widen the scope of a fix that has a concrete incident behind it, so it is left untouched here.
Forward-Port-Of: odoo/enterprise#131457Payroll warnings for split sick leave are now shown even when a leave request has not yet been saved. Employees and payroll teams can also see the warning directly on the employee form, helping avoid missed payroll issues.
Original PR description
Before this commit, the split warning was searched in the database, so a request not saved yet never showed it. The employee form showed no payroll warning either. After this commit, the warning filters the given records, and the banner is also on the employee form. taskid-6578279
This fixes a Belgian payroll rule so the employer contribution uses the correct contribution code. It helps ensure payroll calculations and related reporting are accurate for affected employees.
Original PR description
Small modification referenced in the task. task-6526911
This update improves text readability in Barcode and Master Production Schedule screens by using a lighter background style in affected areas. Users should find labels and information easier to read, reducing visual strain during daily operations.
Original PR description
Before this PR: ================ In several places, text is difficult to read due to the `bg-secondary` class used for styling. <img width="350" height="200" alt="image"…
Before this PR: ================ In several places, text is difficult to read due to the `bg-secondary` class used for styling. <img width="350" height="200" alt="image" src="https://github.com/user-attachments/assets/5d24038e-a63c-457a-a457-91bc75dc615b" /> <img width="350" height="200" alt="image" src="https://github.com/user-attachments/assets/30e78d9d-af1b-4281-bf52-57292ac9dd9f" /> <img width="350" height="200" alt="image" src="https://github.com/user-attachments/assets/45501029-2810-4907-82d0-6356c690e3db" /> After this PR: =============== Replace the `bg-secondary` class with `bg-300` in the affected places, providing better contrast between the text and its background and improving readability across the Barcode and MPS views. <img width="350" height="200" alt="image" src="https://github.com/user-attachments/assets/dc9e242b-1f60-42d3-8e58-b8a4f2b6fc2f" /> <img width="350" height="200" alt="image" src="https://github.com/user-attachments/assets/d8c8ffa0-51b5-4b72-b092-e21b9dd56088" /> <img width="350" height="200" alt="image" src="https://github.com/user-attachments/assets/c3dbfebb-b348-4dee-8933-76acef8e1636" /> Community PR:- odoo/odoo#288498 Forward-Port-Of: odoo/enterprise#131741
Submitting a draft Denmark VAT report no longer triggers an error caused by missing report context. This ensures Danish VAT filings can proceed reliably without users being blocked at submission time.
Original PR description
Currently, an error occurs when the user submits the draft Denmark VAT report. ``` TypeError: AccountReport.get_options() missing 1 required positional argument: 'previous_options' ``` When the user submits the draft Denmark VAT report, it gets the calculated lines of the current report by calling get_options method. However, get_options() requires the previous_options argument [1]. Since this argument is not passed [2], it raises the error. This commit ensures that an empty dictionary is passed as the previous_options argument when getting the report lines. [1]- https://github.com/odoo/enterprise/blob/e2aa3073dafa9377654c761e371a660415db1e88/account_reports/models/account_report.py#L2126 [2]- https://github.com/odoo/enterprise/blob/e2aa3073dafa9377654c761e371a660415db1e88/l10n_dk_reports/wizard/tax_report_wizard.py#L216 sentry-7380293202 Forward-Port-Of: odoo/enterprise#130320
This fixes Turkish Nilvera e-invoices so foreign-currency amounts written in words use fully Turkish currency subunit labels. It prevents mixed-language invoice notes, helping keep e-invoices compliant and clearer for customers.
Original PR description
### Issue before this commit: When generating a Nilvera e-invoice in a foreign currency (e.g., EUR), the amount written in words inside the <cbc:Note> tag contained a mix of languages. While the…
### Issue before this commit: When generating a Nilvera e-invoice in a foreign currency (e.g., EUR), the amount written in words inside the <cbc:Note> tag contained a mix of languages. While the numbers were correctly translated to Turkish, the currency subunit label was fetched using the customer's language. This resulted in a partially translated string (like "... SIFIR CENTS") instead of the expected fully Turkish text (like "... SIFIR SENT"). ### Steps to reproduce the issue: 1. Download Accounting and l10n_tr_nilvera_einvoice 2. Create an API KEY: https://docs.google.com/document/d/1EUzvTBnSm9-VwIfBsX299MHGXIVys-uijnsJ1fpz7vI/edit?tab=t.0#heading=h.e6i8a29lff5t 3. Go to a turkish client on the Accounting tab and click on 'Verify' for the Nilvera status 4. Go to currencies and activate EUR (be sure there is also the translation for currency subunit) 5. Go to invoices, create one for the Turkish customer you already verified setting the currency as EUR and send it with Nilvera 6. See that current output is <cbc:Note>YALNIZ : BEŞYÜZDÖRT EUR SIFIR CENTS</cbc:Note> (Turkish numbers with English subunit) but the expected output is <cbc:Note>YALNIZ : BEŞYÜZDÖRT EUR SIFIR SENT</cbc:Note> (Fully Turkish text) ### Cause of the issue: The issue occurs because the currency_subunit_label field is not translated but fetched using the language of the customer in the invoice. ### Reason to introduce the fix: To ensure that the amount in words inside the <cbc:Note> tag is completely formatted in Turkish, complying with Nilvera and local e-invoicing requirements, regardless of the customer language. opw-6523794 Forward-Port-Of: odoo/enterprise#131873
This fix prevents the Bulgarian SAF-T setup from recreating deleted standard accounts or taxes with incomplete information. It only updates existing standard records, reducing the risk of setup errors or failed upgrades when customers have customized their accounting data.
Original PR description
If a client deletes a standard account or tax, its XMLID can no longer be resolved during the post-init hook. In that case, _load_data() may create a new record using only the provided data, e.g.:…
If a client deletes a standard account or tax, its XMLID can no longer be resolved during the post-init hook. In that case, _load_data() may create a new record using only the provided data, e.g.:
```
('l10n_bg_691001', {'l10n_bg_saft_account_code': '624'})
```
This can lead to incorrect records.
Only update records whose XMLIDs still exist, avoiding the creation of new records when the corresponding standard record has been deleted.
```
File "/home/odoo/src/enterprise/19.0/l10n_bg_saft/__init__.py", line 10, in _add_account_saft_code
Template._load_data({'account.account': Template._get_bg_saft_account_code()})
File "/tmp/tmpbu1ntr1j/migrations/account/0.0.0/pre-ensure-deferred-accounts.py", line 37, in _load_data
return super()._load_data(data, *args, **kwargs)
File "/home/odoo/src/odoo/19.0/addons/account/models/chart_template.py", line 697, in _load_data
created_records[model] = self.with_context(lang='en_US').env[model]._load_records(all_records_vals)
File "/home/odoo/src/odoo/19.0/odoo/orm/models.py", line 5196, in _load_records
records = self._load_records_create([data['values'] for data in to_create])
File "/home/odoo/src/odoo/19.0/odoo/orm/models.py", line 5103, in _load_records_create
records = self.create(vals_list)
File "/home/odoo/src/odoo/19.0/odoo/orm/decorators.py", line 369, in create
return method(self, vals_list)
File "/home/odoo/src/odoo/19.0/addons/account/models/account_account.py", line 1055, in create
)).create(vals_list_for_company)
File "/home/odoo/src/odoo/19.0/odoo/orm/decorators.py", line 369, in create
return method(self, vals_list)
File "/home/odoo/src/odoo/19.0/addons/mail/models/mail_thread.py", line 329, in create
threads = super(MailThread, self).create(vals_list)
File "/home/odoo/src/odoo/19.0/odoo/orm/decorators.py", line 369, in create
return method(self, vals_list)
File "/tmp/tmpbu1ntr1j/migrations/util/orm.py", line 267, in wrapper
return f(*args, **kwargs)
File "/tmp/tmpbu1ntr1j/migrations/base/0.0.0/pre-models-match_uniq.py", line 25, in create
return super().create(vals_list)
File "/home/odoo/src/odoo/19.0/odoo/orm/decorators.py", line 369, in create
return method(self, vals_list)
File "/home/odoo/src/odoo/19.0/odoo/orm/models.py", line 4711, in create
records = self._create(data_list)
File "/home/odoo/src/odoo/19.0/odoo/orm/models.py", line 4887, in _create
cr.execute(SQL(
File "/home/odoo/src/odoo/19.0/odoo/sql_db.py", line 440, in execute
self._obj.execute(query, params)
psycopg2.errors.NotNullViolation: null value in column "account_type" of relation "account_account" violates not-null constraint
DETAIL: Failing row contains (734, null, 1, 1, null, null, null, t, f, f, 2026-08-25 08:18:15.751937, 2026-08-25 08:18:15.751937, no, f, null, null, null, null, 411).
```
upg-4611390
tbg-2902
Forward-Port-Of: odoo/enterprise#129145This fix ensures Belgian 13th month payslips only apply the Special Social Contribution when there is a regular monthly payslip for the same period. It prevents incorrect deductions when the 13th month payment is generated on its own, improving payroll accuracy for Belgian employees.
Original PR description
When we generate a 13th month payslip, we need to check if there is a monthly pay payslip in the same period. If not, the Special Social Contribution will be 0. task-6512347 Forward-Port-Of: odoo/enterprise#131844
When an employee's working schedule is changed, the related leave allocation message now shows the correct contract name and explains what changed. This makes payroll and HR records easier to understand and audit.
Original PR description
When modifying an employee's working schedule via the wizard, the logged chatter message on the leave allocation incorrectly evaluated the contract name to "False" and lacked details on the changes made. This PR fixes the problem by calculating and logging the necessary details regarding the changes. Forward-Port-Of: odoo/enterprise#131956
Belgian payroll no longer applies private car reimbursement when an employee has no joint committee set. The update also standardizes how compensation thresholds are interpreted, reducing incorrect payroll calculations in edge cases.
Original PR description
Issue: - When no JC (joint committee) was specified for given employee, JC302 rule was applied to compute private car compensation. - Unconsistent format for representing intervals by single key in param rules. With key1 < key2 < key3, associated key values to key2 should be read as belonging to [key2, key3[ in one case, and ]key1, key2] in another case. Solution: - No JC, means no private car compensation. - Associated key value to key2 belongs to interval [key2, key3[ - Fix edge cases (value below min requirement for compensation) task: 6531956
Belgian employee departures marked as fixed term now automatically update the related contract version to reflect that status. This keeps HR records accurate and ensures the change is visible in the employee history for easier follow-up.
Original PR description
Set the `fixed_term` boolean field to True on the employee contract version whenever a Belgian departure with the 'Fixed Term' reason is processed. Changes are properly tracked in the employee's chatter. To test: 1. Create a Belgian employee with a contract start and end date. 2. Click on 'End of Collaboration'. 3. Select 'Fixed Term' as the end reason and confirm. 4. Check the employee chatter to verify that 'Fixed Term' is set to True (No -> Yes). Task: 6528392
Several Odoo Enterprise screens now use the correct mobile and debug-mode settings after an underlying framework change. This prevents menus and layouts from silently choosing the wrong desktop view on phones and restores debug-only options where relevant.
Original PR description
Removes depracated `env.isSmall` and `env.debug` and make it throw if used (to prevent forward port mistakes) Community PR: https://github.com/odoo/odoo/pull/287002 Forward-Port-Of: odoo/enterprise#131886
The Indian asset demo data now includes the required model information for asset variants. This prevents installation from being blocked when demo data is loaded, improving reliability for setup and testing.
Original PR description
Asset variants require a model, which was missing from the demo data and blocking installation. This fix updates the demo data and renames the methods to preserve the correct order of execution. task-6580608 ref - https://github.com/odoo/enterprise/commit/3f59a1c4c1c84d5864f68f394589cd46b305f208 Forward-Port-Of: odoo/enterprise#131950
This update removes outdated internal functions across Odoo's core framework and several built-in apps. It helps keep the platform cleaner and easier to maintain, with limited direct impact for everyday users but possible adjustments needed for custom integrations relying on deprecated behavior.
Original PR description
Remove most of deprecated functions. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Odoo removed an unused way of loading chat channels that was no longer called by the interface. The messaging menu already loads the same channels through its normal route, so this cleanup reduces obsolete code and test coverage without changing expected user behavior.
Original PR description
Nothing fetches `channels_as_member`: its client side fetcher was never called, and the messaging menu loads its channels through its own load more route. Remove the handler, that dead fetcher, the loading template it was the only condition of, the mock server counterpart and the performance test. The livechat tests covering it now use the messaging menu load more route, which returns the same channels. https://github.com/odoo/enterprise/pull/131187 Forward-Port-Of: odoo/odoo#287753
An internal messaging performance test was removed because the related check changed in the main Odoo codebase. This keeps the enterprise test suite aligned and prevents test import errors, with no direct impact on end users.
Original PR description
The `channels_as_member` performance test is removed in odoo, adjusting its query count now raises an AttributeError at import. https://github.com/odoo/odoo/pull/287753 Forward-Port-Of: odoo/enterprise#131187
This update modernizes internal component definitions used across Odoo apps such as Accounting, HR, Mass Mailing, Resource, SMS, Survey, and Web. It improves consistency and validation behind the scenes, helping keep the platform maintainable without changing day-to-day user workflows.
Original PR description
See commit messages for details. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#288771
This change removes an obsolete internal setting from the manufacturing work order area. It has no expected impact on daily operations, but it keeps the codebase cleaner and easier to maintain.
Original PR description
Context key hide_unpicked is added with commit cd0ef28d39069857caf0ddb027b9f7415330afce The only place that use the context key was mrp_workorder/views/stock_move_views.xml which was removed in f86a4d39c8c2366fa30fda36bd0de2a086f14aad. This commit removes the unused key.
This update modernizes several user interface components by replacing an older internal configuration pattern with the current validation approach. It helps keep the affected apps maintainable and aligned with the platform framework, with no expected change for end users.
Original PR description
Replaced deprecated uses of `static props` with calls to `useProps()`, providing actual props validation for Owl components.
Whenever possible, also removed "empty" props definition, being either:
- `static props = ["*"]` with no use of `this.props`;
- `static props = {}`.
Forward-Port-Of: odoo/enterprise#131904