Wednesday, September 2, 2026
119 changes · master
Security fixes and vulnerability patches
Email marketing building blocks have been converted to a newer template system, making them easier to update, extend, and maintain across versions. This also reduces security risk from how snippets were previously rendered, adds an easier way to insert unsubscribe links, and prevents product emails from showing internal cost prices.
Original PR description
also modified: html_builder, website Currently, all mailing snippets are "backend" views, instantiated and stored in-database on spin-up, just like website snippets. This has several drawbacks: - mailing snippets cannot be easily updated and/or fixed if they are flawed - new snippets cannot be easily added to older versions - as the snippets are rendered with qweb, they have an elevated level of permission making them an attack vector - "placeholders" for fragments that are editable via plugin (e.g. filling in social links with a company's social info) exist separate from their "filling" This PR intends to fix these issues by turning all backend snippets into frontend Owl templates. To ensure compatibility with the current HTMLBuilder snippet service & existing custom snippets, builtin snippets are seamlessy added to the snippet document when mailing snippets are loaded. task-5477951
New functionality added to Odoo
This update prepares Odoo for Singapore InvoiceNow certification by adding support for Peppol advanced ordering and government e-invoicing requirements. Businesses in Singapore can exchange purchase orders, order changes, cancellations, and compliant invoices with suppliers and government agencies more easily.
Enhancements to existing features
The Timesheets app now directs users to Odoo's newer Timesheets Assistant browser extension instead of the older Activity Watch extension. This helps users find the recommended tool for tracking work activity and completing timesheets more smoothly.
Original PR description
Before this commit, the links pointing to the browser extension of Activity Watch. However, a new extension called Timesheets Assistant has been published by Odoo to improve the Activity watch extension. This commit replaces the links pointed to the browser extension to set the links for Timesheets Assistant browser extension. task-6470304 Forward-Port-Of: odoo/enterprise#129883
Resolved issues and error corrections
This fix prevents time off categories that are not meant to be selectable, such as Attendance, from appearing when users create time off or allocation records. It also avoids confusing balance text being shown for those unavailable categories, helping HR and payroll users choose only valid time off options.
Original PR description
Steps to reproduce: 1. Go to Payroll > Time Off (or Time Off > Management > Allocations). 2. Create a new record or select a cell. 3. Select a time type that has `time_off_selectable` set to False (e.g. Attendance). 4. Observe that the time type is available in selection and appends "(0/0 hours)" to its display name. Cause: - `_compute_display_name` on `hr.work.entry.type` checked `requires_allocation` without verifying if `time_off_selectable` was True. - Selection domains in `hr.leave`, `hr.leave.allocation`, and batch generation wizards did not filter out non-selectable time off types. Solution: - Check `time_off_selectable` alongside `requires_allocation` in `hr.work.entry.type._compute_display_name`. - Enforce `time_off_selectable = True` in selection domains across `hr.leave`, `hr.leave.allocation`, `hr.leave.allocation.generate.multi.wizard`, and `hr.leave.generate.multi.wizard`. Task: 6518178
Features or functions removed from Odoo
An unused local test script was removed from the HTML editor area after being committed by mistake. This cleanup has no expected effect on users or business workflows, but keeps the codebase tidier and avoids confusion for future maintenance.
Original PR description
Remove test_range.js, which was accidentally committed in 27e585796fe1243fc3487c3e236ba704ebcb976f. It’s only a local jsdom test script, isn’t used anywhere. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Code cleanup and technical improvements
This cleanup removes two unused files from the Point of Sale module. It helps keep the codebase simpler and easier to maintain, with no expected change for users.
Original PR description
This commit removes the following unused files: - `static/lib/waitfont.js` - `static/src/app/utils/debug.js` --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
The Singapore IMDA requires a Solution Provider to complete a certification process (InvoiceNow-Ready Solution Provider / IRSP) before its users can be onboarded to InvoiceNow. Part of that…
The Singapore IMDA requires a Solution Provider to complete a certification process (InvoiceNow-Ready Solution Provider / IRSP) before its users can be onboarded to InvoiceNow. Part of that certification exercises the Peppol Advanced Ordering flow (order → order response → order change/cancellation) in addition to plain invoicing, and it requires special handling for B2G invoicing to Singapore government agencies (AGD). This PR is the groundwork for that certification and for the eventual Peppol corner 5 (CTC/government) model — it does not implement corner 5 itself, but puts in place the SG-specific Peppol document types, order exchange, and B2G invoice rules IMDA's test scenarios exercise.
### New modules
#### l10n_sg_sale_peppol (auto-installs with l10n_sg + sale_edi_ubl)
Receives Peppol UBL BIS Advanced Order documents (order, order change, order cancellation), decrypts/imports them into sale orders, and sends back order responses. This is the "seller" side of the advanced-ordering flow required by IRSP.
#### l10n_sg_purchase_peppol (auto-installs with l10n_sg + purchase_edi_ubl_bis3)
The "buyer" side: exports purchase orders as Peppol UBL BIS Advanced Order documents (order, order change, cancellation) and processes the resulting order responses/balances from the supplier.
#### l10n_sg_b2g (depends on l10n_sg_ubl_pint + l10n_sg_sale_peppol)
Implements Singapore's AGD (statutory board) B2G e-invoicing rules — a prerequisite specifically for selling to government vendors. Adds:
- A new res.partner.invoice_edi_format option ("Singapore (AGD B2G)") with a dedicated EDI encoder/constraints.
- Reference data: statutory boards as res.partner records tagged via a new res.partner.category, a new model for sub-business units of those boards, government-mandated payment terms, and a dedicated freight-charge product rendered as a document-level charge (per AGD spec).
- Overrides on account.move.send to control file embedding/attachment requirements specific to AGD submissions.
### Changes to existing modules
#### l10n_sg
Now depends on account_peppol. Adds a post-init hook that registers SG's Peppol document types on install and triggers auto-registration when an SG company (EAS scheme 0195) first becomes a Peppol receiver; an uninstall hook deregisters them. Adds representative name/email fields to the KYC registration wizard (IMDA requires a named representative) and hides the generic Peppol role-selection UI in settings since SG's flow is fixed.
#### l10n_sg_ubl_pint
Registers SG PINT invoice/credit-note document types with account_peppol. Also extended to stamp BuyerReference (BT-10) from invoice.ref, override OrderReference with the Peppol order id + sale order name (instead of BIS3's default of using the invoice name), and add OrderLineReference/LineID per invoice line — because IMDA's advanced-order test scenario requires invoices to trace back to the originating PO and PO lines.
#### account_peppol — several supporting changes:
- Recognizes Singapore's UEN-based Peppol participant id format (SGUEN<UEN> under scheme 0195) as a valid identifier.
- Promotes SG to PEPPOL_DEFAULT_COUNTRIES, adds a kyc_pending proxy state for SG's KYC step, and adds the auto-register cron that l10n_sg triggers.
- Generalizes _peppol_import_invoice → _peppol_import_document with a document-type gate, so the polling/import flow can dispatch to order-import logic (used by l10n_sg_sale_peppol) instead of assuming every inbound document is an invoice.
#### sale_edi_ubl
When importing UBL BIS order documents, line-level charges are now linked to their corresponding order lines via linked_line_ids (previously imported as unrelated standalone lines), which the SG advanced-order flow relies on to keep charges tied to the PO line they apply to.The timesheet timer now uses only the user's recent timesheet activity from the past month when suggesting a task for a selected project. This avoids filling in old, irrelevant tasks and keeps time entry suggestions aligned with current work.
Original PR description
When selecting a project in the timesheet timer, the prefilled task could be one the user last logged time on years ago, which is no longer relevant. The prefill now only considers timesheets from the past month and follows the user's most recent one: if that timesheet has no task, none is prefilled rather than reaching further back. task-6485260 Forward-Port-Of: odoo/enterprise#128738
Status buttons now show clearer visual feedback for hover, pressed, open, and current states. This makes workflow progress indicators easier to understand and avoids confusing highlights after a user clicks a step.
Original PR description
- requires https://github.com/odoo/enterprise/pull/130030 The statusbar buttons painted `:hover` and `:focus` alike, so a button stayed highlighted after being clicked. That rule is also more…
- requires https://github.com/odoo/enterprise/pull/130030 The statusbar buttons painted `:hover` and `:focus` alike, so a button stayed highlighted after being clicked. That rule is also more specific than Bootstrap's `.btn:first-child:active` and `.btn.show`, so it kept winning the cascade while the cursor was on the button: the pressed state only appeared once the pointer left it, and an open `...` dropdown read as merely hovered. Restrict the rule to `:hover`, and give `:active` and `.show` a declaration of their own on a dedicated `--o-statusbar-background-pressed` token. The current step was painted through the `disabled` attribute, which tied its look to the button being disabled and forced anything restyling the bar to go through `--btn-disabled-bg`. Paint it from its own `.o_arrow_button_current` class instead, declared last so it outranks the states above, and leave `:disabled` with nothing but the muted color of the steps that are not the current one. The three backgrounds are no longer declared on `.o_statusbar_status`: they are read where they are used, with the `btn-secondary` design map as a fallback. An edition or a component can now set `--o-statusbar-background-hover`, `-pressed` or `-current` on the bar without having to reach into these rules. The hr timeline only overrode these states to compensate for a hover as dark as the selected version: the reviewed web states cover it, so the override goes away. task-6518027 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The page navigation control now uses the standard button group style already used in similar Odoo toolbars. This reduces duplicated styling and keeps the control panel visually aligned, with only a minor interface consistency impact for users.
Original PR description
The pageSwitcher shipped its own SCSS duplicating the `o_switcher` meta-component from web_enterprise: same padding, background, border and radius, same `--btn-*` overrides. Drop it and let the pageSwitcher render as a regular `btn-group`, like the gantt and calendar toolbars. The pageSwitcher sits next to the view switcher, which `o_switcher` makes taller than a standard button, so stretch `.o_cp_pager` to keep the control panel row on a single height. No effect in community or on mobile, where nothing in that row is taller than a button. The group header pageSwitcher no longer has a wrapper to cancel out, so its reset in `list_renderer.scss` goes away too. task-6518267 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The Project To-Do onboarding flow now shows refreshed screenshots that better match the current product experience. This helps new users follow setup guidance more easily and reduces confusion during onboarding.
Original PR description
Update the screenshots of the onboarding to-do --- task-6443670
This update lets Odoo modules choose where editor placeholder text appears instead of forcing it into the default content block. It keeps the existing behavior by default while reducing extra customization work for modules that need placeholders in places such as titles.
Original PR description
Before the placeholder was tied to the default block, so a module that wanted it somewhere else (like a title) had to rewrite the whole plugin. This commit lets a module register its own target instead, keeping the current behavior when nothing overrides it. task-4496371 requires: https://github.com/odoo/enterprise/pull/116529 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Lead creation from live chat and messaging channels is now easier to customize across Odoo. This helps future integrations like WhatsApp or social messaging set the right tracking information without extra dependency work, while keeping live chat defaults unchanged.
Original PR description
Extract lead creation values from _convert_visitor_to_lead into a _prepare_lead_create_values hook method on discuss.channel in the base crm module. This allows other modules (e.g. whatsapp_crm) to override lead values without depending on crm_livechat. The livechat UTM values (source=Livechat, medium=Website) are kept as defaults in the base method since livechat is considered the primary use case, avoiding the need for a whatsapp_crm_livechat bridge module. Task-3964124
Status bars in Enterprise now use clearer visual states for hover, press, and the current step. This reduces confusion by making it easier to see which step is selected in both light and dark mode.
Original PR description
- requires https://github.com/odoo/odoo/pull/285945 The statusbar now reads its hover, pressed and current backgrounds from `--o-statusbar-background-hover`, `-pressed` and `-current`, falling back to the `btn-secondary` design map when nothing declares them. Enterprise had no statusbar stylesheet, so the bar was left with those fallbacks: the hover was as dark as the current step, which made the bar look like it had two selections, and the pressed state was hard to tell apart from either. Declare the three tokens on the gray scale instead, each state a step apart, with the hover and pressed hints kept translucent so they stay lighter than the current step. Dark mode gets its own values: the scale reads the other way round there, so the same three tokens move up a step to stay visible on a dark bar. task-6518027
This update makes India payroll Form 138 setup clearer and more reliable by improving date handling, file naming, and employee filtering. It also prevents accidental creation of responsible person records from settings, helping keep configuration data cleaner.
Original PR description
this PR - removes custom `format_date` by using `odoo.tools.format_date` - adds a placeholder for filename in Form 138 form view (because the default value was `false`) - uses employee's `country_code` to filter in the settings rather than employee's parter's `country_code` (to save the headache) - also restricts on-the-fly creation of `responsible_person` in settings. [Task #6522078](https://www.odoo.com/odoo/project/1251/tasks/6522078)
The Knowledge app receives visual refinements that make screens, comments, dialogs, and article helpers feel more consistent and easier to read. These updates improve day-to-day usability for teams working with knowledge articles, templates, and related website or AI-assisted features.
Original PR description
*: accountant_knowledge, ai_knowledge, website_knowledge Prior to this commit, parts of the Knowledge module felt uneven and visually inconsistent, with some spacing, alignment, and readability issues. This commit refines the UI to make the module cleaner, more coherent, and easier to read where possible. requires: https://github.com/odoo/odoo/pull/278079 task-4496371
The appointment calendar now shows all bookings for the selected appointment type, even when no internal user was assigned. This prevents bookings from being hidden and makes it easier for staff to review and manage appointments in the calendar view.
Original PR description
If you add a booking but forget to specify an internal user, you won't find it at all unless you know the customer's name, go to list view or gantt view and look for a while. The calendar view's only applied filter should be the appointment type. All bookings should be visible in it. Task-6499578
The accounting reports interface has been updated to use a safer shared mechanism for its button bar. This is an internal improvement that should help keep report actions reliable without changing day-to-day user workflows.
Original PR description
Following odoo/odoo@324ab8b5080fc35367b2e7a63d33e3fa0674a2e1, usePlugin can now be safely used.
Leads created from WhatsApp conversations are now automatically tagged with WhatsApp as the source, Messaging as the medium, and the related WhatsApp account as the reference. This improves campaign attribution and helps teams better understand which WhatsApp channels generate sales opportunities.
Original PR description
When a discuss channel has a WhatsApp account configured, leads created via /lead should use WhatsApp as source, Social Media as medium, and reference the WhatsApp account as utm_reference. Add WhatsApp UTM source record in whatsapp module and override the new _prepare_lead_create_values hook in whatsapp_crm. Task-3964124
The timesheet assistant now makes better suggestions for Gmail activities by prioritizing learned subject-based matches before falling back to email matching. When an email is shared by multiple contacts, it also prefers the contact tied to a matching user, reducing incorrect or inconsistent timesheet suggestions.
Original PR description
Forward-Port-Of: odoo/enterprise#128879 Forward-Port-Of: odoo/enterprise#127850
Visitor records now show more meaningful website activity, including visits to blog posts, events, courses, and products instead of only generic page URLs. This gives teams clearer insight into what content visitors engage with, while the visitor language field is made read-only to avoid confusion.
Original PR description
*: website_blog, website_event, website_profile, website_sale, website_slides This PR improves the visitor page tracking system and fixes several inconsistencies in the visitor interface. Key changes: - Make the visitor language field read-only to avoid misleading UI, as changing the dropdown does not trigger a real language switch. - Display the related product name alongside product URLs to allow proper grouping and filtering by product. - Extend visitor page tracking to non-product content so that interactions with blogs, events, and other pages are properly recorded. This provides better visibility into visitor activity across different website modules. task-4850073
Duplicated records with a Name field will now automatically get a clear copy label by default. This reduces repetitive setup across many Odoo apps and helps users distinguish originals from copies, including for fields created with Studio.
Original PR description
Make char fields named "name" use `mark_as_copy` by default for the `copy` attribute. This is a very common use case and it will also work for studio fields. https://github.com/odoo/enterprise/pull/129451 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Duplicated records across many Odoo apps will now get clearer default names, making copied items easier to identify and manage. This improves day-to-day usability and consistency when users duplicate templates, rules, tickets, assets, and similar business records.
Original PR description
https://github.com/odoo/odoo/pull/284881
Appointment schedules now show unavailable times more consistently in both Gantt and calendar views. This helps staff quickly see when users or resources cannot be booked, including when slots are limited to specific people or resources.
Original PR description
Commit 1: Gantt View ------------- In the gantt view of the appointment, when the user/resource is unavailable, related area is greyed out for the better visual feedback. Though when the slot is…
Commit 1: Gantt View ------------- In the gantt view of the appointment, when the user/resource is unavailable, related area is greyed out for the better visual feedback. Though when the slot is restricted to some users/resources, gantt view didn't grey out to show others unavailable. This commit makes the gantt view consider slot restrictions to grey out slots for the users/resources not in the slot's restricted users/resources. Commit 2: Calendar View ------------- Before this commit, slot unavailabilities were visible in the gantt view of the appointment events but not shown in the calendar view. This commit adds the slots unavailabilities in the calendar view of appointment events. The related area in the calendar is greyed out when the appointment has no slot available at that time. ### Technical We're using the background events to highlight unavailability in the region except the slots. Also, slots are added as background events with display as `inverse-background`. As the name implies, the display `inverse-background` paints the region except the event For more information: See https://fullcalendar.io/docs/background-events Task-5416962
Turkish payroll now distinguishes self-employed workers from regular employees for social security treatment. This allows salary calculations and payroll structures to better reflect the different insurance rules that apply to 4b self-employed Turkish citizens.
Original PR description
In order to cater for the different insurance policies for different employee types (self-employed vs normal employees), social security status is a needed field for salary computation. Moreover, different salary structure was added specific for the 4b (self-employed) turkish citizens. Task: 6438815
Marketing automation jobs now process campaigns individually and record progress, so one failing campaign is less likely to stop automation for all campaigns. Campaign managers also get clearer failure information and logs to help identify and resolve synchronization or execution issues.
Original PR description
Rationale Current crons of marketing automation are not really managed. Campaign may fail due to various errors either during activity execution (mail server issue, whatsapp issue, ...) or when…
Rationale Current crons of marketing automation are not really managed. Campaign may fail due to various errors either during activity execution (mail server issue, whatsapp issue, ...) or when enrolling new participants (notably MemoryError or TimingError due to current implementation). This leads to cron logging errors regularly on some campaigns (typically Memory or Timing errors) then deactivating the cron. This is extremely annoying as it impacts all campaigns. Specifications Define specific cron methods for crons, doing a search and looping on campaigns to execute. Each campaign therefore runs individually. Use basic cron progress commit, trying to log remaining and done campaigns, without specific error management currently. Logging progress in crons allows to tag it as "alive" and avoid the cron to be put in error and deactivated if a campaign fails too much time in a row. Improve cron management, in order to better warn from synchronize or execution issues. We move towards model-based management, which means considering a failure as "managed". It is now the role of marketing managers to keep an eye on their campaign, helped by failure fields and logs. Specifications * add error fields on campaign model; * manually commit progress and/or rollback; * log errors on campaigns; * be sure failing campaigns do not retry in loops; Task-6425785
Appointment pages are now tracked as appointment types rather than only plain web addresses. This helps teams see which appointment offerings visitors viewed and how often, making visitor interest easier to understand and filter.
Original PR description
This PR extends the visitor page tracking system to ensure that appointment pages accessed through `/appointment` are properly recorded in the visitor page views list. Key changes: - Enable visitor page tracking for `/appointment` appointment pages. - Ensure appointment page visits appear in the visitor page views list. task-4850073
The Point of Sale dashboard graph now uses tighter spacing in its card to better match the accounting dashboard design. This is a small visual polish change that makes dashboards feel more consistent across Odoo.
Original PR description
We removed the padding on the left, right and bottom of the graph in the kanban card. task-6488005
Quotation and invoice buttons now show more accurate totals, including taxes, currencies, and exchange-rate conversion where needed. Related list views are cleaner and more consistent, with cancelled quotations hidden by default so sales teams focus on active opportunities.
Original PR description
\* = account, crm, event_booth_sale, event_sale, link_tracker, mass_mailing, mass_mailing_sale, mass_mailing_sms, pos_event, sale, sale_crm, sale_projet This PR improves the UI related to the…
\* = account, crm, event_booth_sale, event_sale, link_tracker, mass_mailing, mass_mailing_sale, mass_mailing_sms, pos_event, sale, sale_crm, sale_projet This PR improves the UI related to the quotations and the invoices stat buttons. Multiple commits have been created for that: - Commit 1 removes the CrmTeam.invoiced and CrmTeam.invoiced_target as they are not longer used by the progress bar inside the sale team kanban which has been previously deleted. As the progress bar is not being used, the "sales_team_progressbar" has also been removed. - Commit 2 excludes the account moves with "entry" as move_type to get the total invoiced amount due to a mailing as those account moves are journal entries and are not yet invoiced. - Commit 3 converts the amounts of the moves into the current company currency before calculating their sum. - Commit 4 displays the currencies of the total amounts shown in the invoices stat buttons. - Commit 5 displays the amounts including the tax in the stat buttons redirecting to the invoices list views. - Commit 6 moves the rounded corners of campaign stat buttons at the right places. - Commit 7 improves the display of the UI related to the stat buttons to get more consistency across screens. - Commit 8 hides cancelled quotations in list views using a new default filter. Then, it also adapts the counts displayed in the stat buttons redirecting to those views. Those quotations must be hidden as they will not lead to anything. Enterprise PR: https://github.com/odoo/enterprise/pull/99697 Upgrade PR: https://github.com/odoo/upgrade/pull/8989 Task-5258611
Messaging and live chat now use more efficient internal data storage for lists, selections, and record lookups. This should make mail-related screens and large message datasets respond faster without changing user-facing behavior.
Original PR description
Owl tracked a signal collection through its own atom: any write notified every reader, and a collection mutated in place cannot afford that, so mail uses proxies instead. Owl now tracks a signal…
Owl tracked a signal collection through its own atom: any write notified every reader, and a collection mutated in place cannot afford that, so mail uses proxies instead. Owl now tracks a signal collection per key, and unlike a proxy it hands its values back raw. The first commit converts three collections: a record list, which builds the pair by hand as a signal read through a proxy, the Set of message ids `useMessageSelection` holds inside a proxied class, and the active columns of the activity view, a proxied object that turns the activity type ids into strings. The second one is the records of a model, kept by local id in a proxied object. Reading one walks the value to decide whether it can be made reactive, which calls `Object.prototype.toString` on a record proxy and so goes through `proxyGet`, only to hand back the very same object: records are `markRaw`. That walk is most of what `Model.get()` costs, and `preinsert` calls it for every record entering the store. Over a store of 20000 records a lookup drops from 2.0us to 0.45us. `Model.records` becomes a `signal.Map` behind an accessor, so it stays a property and the call sites only change API: ```js Model.records[localId] -> Model.records.get(localId) delete Model.records[localId] -> Model.records.delete(localId) Object.values(Model.records) -> [...Model.records.values()] ``` `.find`, `.some` and `.reduce` take the iterator, so they short-circuit without building an array. The `asProxy` fields keep their proxy: observing the nested content is what the option is for. Enterprise counterpart: `[PERF] sign, voip: adapt to the record map`, same branch name. https://github.com/odoo/enterprise/pull/129723
The update makes campaign, social post, and rental CRM sales buttons clearer and more consistent, including better icons, button styling, and visible currency symbols. Invoice totals are now more accurate because they include taxes and correctly convert amounts from different currencies before showing totals.
Original PR description
\* = sale_commission, sale_renting_crm, social, social_push_notification, social_sale This PR improves the UI related to the quotations and the invoices stat buttons. Multiple commits have been created for that: - Commit 1 remove a view specifying only CrmTeam.invoiced_target which has been deleted as it is not used. - Commit 2 converts the prices of the moves into the current company currency before calculating their sum. - Commit 3 displays the currencies of the total amounts shown in the invoices stat buttons. - Commit 4 displays amounts including tax in the stat buttons redirecting to the invoices list views. - Commit 5 moves the rounded corners of campaign stat buttons at the right places. - Commit 6 improves the display of the UI related to the stat buttons to get more consistency across screens. Community PR: https://github.com/odoo/odoo/pull/236080 Task-5258611
This update improves how Sign and VoIP look up internal records, aligning them with a faster shared approach used elsewhere in Odoo. Business users may see small performance gains in related activity, call history, and softphone interactions, with no change to features or workflows.
Original PR description
Enterprise counterpart of "[PERF] mail: speed up a record lookup by local id", which explains the why.
Object.values(Model.records) -> Model.records.values()
https://github.com/odoo/odoo/pull/285358When a sales order is confirmed, product descriptions from sales order lines are now carried over into the related planning slot notes. This helps teams see important service or product details directly in planning without re-entering information.
Original PR description
Previously, when we added a description to the SOL, it was not directly added as a note in planning_slot. From this commit, the product description will be added whenever a Sales Order gets confirmed. Also, some test cases are added to ensure the feature works correctly Task-6285798
Gantt schedules now consistently show a leading group for items that do not have a value in the selected grouping field, instead of hiding them. This helps teams spot unassigned or incomplete scheduling records across apps such as Planning, Projects, Attendance, Appointments, Time Off, and Manufacturing, while also standardizing behavior across those views.
Original PR description
*: appointment, hr_attendance_gantt, mrp_workorder, planning, project_enterprise Gantt views grouped by a field now always show a leading "Undefined <Field>" group for records with no value on that field, instead of silently omitting them (only applies if the groupBy field is not required). Rows with no records are also skipped by GanttRenderer's column-folding computation when grouped. This is now handled once in the base GanttModel/GanttRenderer, replacing duplicated, inconsistent per-addon logic in planning (the "Open Shifts" whitelist/rename, alphabetical row sorting) and project_enterprise (the user_id-only fake group, alphabetical row sorting). The "Open Shifts" rename is now handled model-wise instead (through falsy_value_label). task-6279702
The demo worksheet for device installation and maintenance now looks more realistic, with shorter labels and a clearer two-column layout. Some sample interventions also include completed worksheet details, helping customers better understand how the feature can support real field service work.
Original PR description
This commit reworks the "Device Installation and Maintenance" worksheet template to display its fields in two columns using separators, and shortens the labels so the demo represents a realistic use case and customers can see themselves using the feature. It also fills in the worksheet of some interventions in the demo data. task-6455863
This change makes Odoo's live messaging checks more efficient by reusing session information when it has not changed. It reduces server CPU work during high websocket traffic, improving capacity and responsiveness for busy deployments.
Original PR description
Each outgoing websocket message has to validate the session. That validation currently goes through a chain of expensive operations: json.dumps, json.loads, MutableMapping.update, in the middle of…
Each outgoing websocket message has to validate the session. That validation currently goes through a chain of expensive operations: json.dumps, json.loads, MutableMapping.update, in the middle of the bus dispatcher's hot path. This runs several times per second under load. A load test with 1k sockets and 400 messages/sec, profiled with py-spy over a 50s window, showed ~46% of active CPU time (103 of 222 samples) spent in `_kick_invalid_sessions`. The gevent server runs on a single thread, so wasted CPU work here directly caps its throughput. To solve this issue, we can keep a small sid -> (mtime, inode) LRU. Use the in-memory session when the file is unchanged since we last checked it. `open`+`fstat` is used instead of `stat` to force NFS clients to revalidate their attribute cache instead of trusting a possibly stale one. The inode is tracked alongside the mtime as a tie-breaker for filesystems whose mtime clock resolution can make two close rewrites collide. Memory overhead is negligible (~2MB for the whole cache). With this fix, the same load test and profiling setup shows `_kick_invalid_sessions` down to ~20% of active CPU time (35 of 175 samples), more than halving the CPU share spent validating sessions. follow-up of task-5449503
The attachment tab is now visible when creating or editing a work order operation, even before the operation has been saved. This removes an extra save step and makes it easier for users to add relevant documents at the right time.
Original PR description
Attachment tab is not visible if work order operation is not set. This commit makes sure it is always visible, so there is no need to save the operation beforehand task-6392087
Cart cleanup now keeps appointment booking fee lines even when their products are not visible for regular shop purchase. This prevents customers' calendar bookings from being accidentally removed during checkout cart maintenance.
Original PR description
website_sale now drops cart lines whose product cannot be bought on the shop. Booking fee products are unpublished and removing such a line would unlink the customer's calendar bookings. See : - https://github.com/odoo/odoo/pull/286261
The HTML editor now keeps the table menu out of the way when cells are selected and provides a clearer compact toolbar for table editing. This makes table formatting, alignment, and cell merging easier to find and reduces overlapping controls while editing content.
Original PR description
## Commit 1: [REF] html_editor: move merge/unmerge cell from table menu to toolbar Related commit: https://github.com/odoo/odoo/commit/c5080ae0fec749ca9b95674bea4f99129b17983d Before this commit: the…
## Commit 1: [REF] html_editor: move merge/unmerge cell from table menu to toolbar Related commit: https://github.com/odoo/odoo/commit/c5080ae0fec749ca9b95674bea4f99129b17983d Before this commit: the table cell merge and unmerge options are inside table menu. After this commit: now the merge/unmerge are toolbar items. The related tests are moved to the misc.test.js. Also added tests related to the merge/unmerge buttons' visibility, e.g. when the single row/column selection includes a merged cell and a unmerge cell, both buttons should be shown. Note that: the general table menu item visibility logic in the template is kept. Because it's not specifically related to the table cell merging. ## Commit 2: [FIX] html_editor: close table menu when one or more cells are selected Before this commit: the table menu is shown when one or more cells are selected, which is overlapping with the toolbar. After this commit: the table menu is only shown when there's no selected cell. ## Commit 3: [IMP] html_editor: add compact table toolbar and improve its grouping Before this commit: we have the normal compact toolbar when selecting table cells, the table related buttons are grouped in a single group in the toolbar. After this commit: 1. We now have 3 table button groups based on their usage, e.g. group 1: style or border; group 2: vertical alignment: group 3: cell merge 2. We introduced a new toolbar namespace: table, as a compact expandable table toolbar when selecting table cells. The table toolbar includes basic text formatting and the table related buttons. 3. We removed the unmerge cell button. Now we only use the merge cell button to control merge/unmerge cell. The merge button is only activated when only selecting a merged cell, and clicking it will unmerge the cell. Note that the logic of merge and unmerge cell are still kept separate, the functionality is done in a toolbar tweaking way instead of merging these two use cases. By doing this, we keep the functionality modular and easier to maintain. Also will be easier to adapt the merge button logic in the future if needed. The tests are adjusted accordingly. task-5973036 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The mail module now formats warranty information in a standard JSON format before sending it to the warranty server. This helps ensure the server can reliably read the information and reduces the risk of processing errors.
Original PR description
Format the publisher warranty message using json.dumps() instead of Python's native str() representation. This ensures serializeid JSON serialization for the payload sent to the warranty server. Forward-Port-Of: odoo/odoo#285632 Forward-Port-Of: odoo/odoo#283139
Subscriptions with delivery-based products now show a warning when delivered items still need to be invoiced. This helps users create the next invoice manually and avoid automatic billing that could reuse an existing payment and charge the customer twice.
Original PR description
Before this commit: When a subscription mixes an order based invoice policy product with a delivery based invoice policy product (or has only delivery based invoice policy products), paying through the portal only invoices the order based product, because the delivery based product is only invoiced after it is delivered. Once the delivered quantity is set and the recurring invoice cron creates the next invoice on the next invoice date, the automatic payment flow can charge the delivered based product's payment a second time on that invoice by reusing the existing payment transaction, applying the payment twice. After this commit: A `has_pending_delivery_invoice` field is computed on the subscription and a warning banner is shown on the form when a delivery based invoice policy line has been delivered but not yet invoiced, telling the user to create the next invoice manually instead of letting the cron invoice and pay it automatically. taskid-4250892
This update prepares the sales discount wizard so its discount values can be reused by subscription-related workflows. It helps keep discount handling more consistent across sales processes, with minimal direct impact on day-to-day users.
Original PR description
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
Belgian payroll employee types are now consistently assigned to Belgium, reducing the risk of incomplete or inconsistent employee setup data. The update also aligns seasonal employee type records with the shared HR definition to avoid duplicate configuration.
Original PR description
Some employee types from the Belgian localization do not have the country id set to Belgium. This commit sets all default employee type country_id to Belgium. The field country_id for hr.employee.type is now required, without enforcing NOT NULL constrain at the sql table level. Instead a constrain is used on the server side and an attribute on the frontend xml to mimic the same behavior. The goal is to ensure data integrity. New sql constrains only applied to a l10n would cause issue in case of an install/uninstall of that same l10n. Additionally, a standalone record for seasonal employee existed in the l10n, along with one hr/. This commits reuse the parent one in hr/ and deletes the standalone record. task: 6511484
Subscriptions aligned to calendar periods now show and charge the prorated amount upfront when customers start mid-period. This makes checkout, invoices, and portal information clearer and more accurate for customers buying prorated plans.
Original PR description
Before this commit, the billing logic for subscriptions set to "Align to calendar period" was unclear. If a customer started a subscription mid-month (e.g., Nov 12 ), the system would adjust the prorated amount for the initial partial period on the second invoice rather than the first. After this commit, now subscriptions starting mid-month generate an initial invoice for only the prorated amount (e.g., for Nov 20–30), providing customers with an accurate and transparent cost at checkout and in their portal. and E-commerce checkout page display correct prorated amount and charge according Impact: Enhanced user experience on the checkout and portal pages for prorated plans. Technical notes: - On quotation confirmation, a prorated adjustment line is added for the initial partial billing period. taskid-5066496
The Helpdesk team card layout has been adjusted so the email alias lines up neatly with the team name. This small visual improvement makes the Helpdesk settings screen look cleaner and easier to scan.
Original PR description
In this commit, we remove the margin before the mail alias, ensuring aligment within the helpdesk team card. task-6416578
Managers now get a dedicated Time Off calendar experience that shows the relevant employee when reviewing or creating time-off entries. This reduces confusion, removes manager-specific balance information from the management view, and makes employee-based time-off type selection work consistently.
Original PR description
Purpose: - At the moment, the calendar view under Management > Time Off is the same as My Time > Days Off for a manager. The only difference is the 'Waiting for me' filter applied by default. A…
Purpose: - At the moment, the calendar view under Management > Time Off is the same as My Time > Days Off for a manager. The only difference is the 'Waiting for me' filter applied by default. A manager can thus not see when clicking on an entry who the time-off is related to without opening it. This PR includes: - Removed the banner showing the manager's own time-off saldo from the Management > Time Off calendar view. - Added the Employee field to the approval popup opened when clicking an existing time-off entry from this calendar. - Added the Employee field to the New Time Off popup opened when clicking a dat on this calendar, and stopped defaulting the employee to the logged-in manager. - Added a dedicated full-page 'New Time Off' action for the manager view, reusing the existing manager form, so the employee field behaves consistently. - Fixed the Time Off Type selection not updating correctly when a manager picks a different employee, by aligning the domain with the one already used on the manager form. - Hid the 'New Allocation Request' option from the New button dropdown on this view, since allocations are not managed from this tab, and switched to a plain button when only one action remains. task-6343922
This change improves pivot reports by allowing grouped data to be expanded directly, making it easier for users to drill into summarized information. It helps business users explore report details faster without switching views or changing report setup.
Original PR description
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
The test suite now checks the most recent document in the same order users see it in the interface. This reduces confusing test behavior and helps prevent false failures when internal data ordering changes.
Original PR description
Because of missing `sorted()`, we were asserting the last document using the cache order and not the order in which they are in the UI. That brings confusion when reading the code and leads to failing tests if, for some reason, the cache is refreshed.
Payroll payment reports now use a shared way to choose the right export format for each country. This reduces repeated code across local payroll modules, making future updates easier and lowering the risk of inconsistent payment report behavior.
Original PR description
* = l10n_{ae, au, ch, hk, in, sa, us}_hr_payroll, hr_payroll_account_iso2002
Currently, the `action_payslip_payment_report` method in `hr.payroll` and the `action_payment_report` method in `hr.payroll.run` are overridden across multiple localization modules to modify default_export_format.
This results in code duplication, higher maintenance effort, and a risk of conflicts or inconsistencies, since the same method is repeatedly overridden in different localizations just to update a single context value.
This commit will improve the current code by introduce the helper methods `_get_payslip_export_format (hr.payslip)` and `_get_payslip_run_export_format (hr.payslip.run)` to compute `default_export_format`.
This allows Allows localizations to override only these methods instead of full report actions, reducing duplication and avoiding conflicts.
sentry-7391832811Ecuadorian electronic invoices and delivery guides can now include the third-party billing software provider's RUC, as required by SRI regulations. Businesses can enter this value in invoicing settings, and it will be sent electronically and shown on printed documents automatically.
Original PR description
Purpose: SRI Resolution requires taxpayers using 3rd-party billing software in Ecuador to report the software provider's RUC on all electronic documents and printed representations (RIDE). A new system parameter is introduced and displayed in Invoicing > Setting > Ecuadorian Localization > Electronic Invoicing, so users can add their software provider's RUC. This value will be automatically sent to the EDI and displayed on the report. task-6432810 Forward-Port-Of: odoo/enterprise#129456
This update brings Odoo's spreadsheet engine up to the latest version, improving stability, chart behavior, dashboards, exports, and dark mode display. It also includes internal cleanup that helps keep spreadsheet features more reliable and easier to maintain.
Original PR description
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/23c00bb8b0 [REL] 19.5.0-alpha.15 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0)…
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/23c00bb8b0 [REL] 19.5.0-alpha.15 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0) https://github.com/odoo/o-spreadsheet/commit/281339d378 [REF] plugins: clarify the separation of concerns between plugin types [Task: 6428159](https://www.odoo.com/odoo/2328/tasks/6428159) https://github.com/odoo/o-spreadsheet/commit/294ff95a2a [MOV] doc: move store engine doc outside of src [Task: 6428159](https://www.odoo.com/odoo/2328/tasks/6428159) https://github.com/odoo/o-spreadsheet/commit/236bd370ac [IMP] documentation: update documentation about plugin differences [Task: 6428159](https://www.odoo.com/odoo/2328/tasks/6428159) https://github.com/odoo/o-spreadsheet/commit/f22a7ae092 [IMP] plugins: evaluation plugins cannot handle UI commands [Task: 6428159](https://www.odoo.com/odoo/2328/tasks/6428159) https://github.com/odoo/o-spreadsheet/commit/bf27f07708 [IMP] commands: rename isEvaluationCommand to isDispatcheableEvaluationCommand and related types [Task: 6428159](https://www.odoo.com/odoo/2328/tasks/6428159) https://github.com/odoo/o-spreadsheet/commit/cdcc389680 [IMP] tests: add a test to ensure UI getter are not accessible [Task: 6428159](https://www.odoo.com/odoo/2328/tasks/6428159) https://github.com/odoo/o-spreadsheet/commit/b98be4ee92 [FIX] plugins: export PluginRegistry for type generation [Task: 0](https://www.odoo.com/odoo/2328/tasks/0) https://github.com/odoo/o-spreadsheet/commit/26f312224d [IMP] plugins: remove evaluationUIPluginRegistry [Task: 6428159](https://www.odoo.com/odoo/2328/tasks/6428159) https://github.com/odoo/o-spreadsheet/commit/cc6932828a [REF] plugins: SubtotalEvaluation is now an evaluation plugin [Task: 6428159](https://www.odoo.com/odoo/2328/tasks/6428159) https://github.com/odoo/o-spreadsheet/commit/7ac1a5adcb [REF] plugins: FilterEvaluation is now an EvaluationPlugin [Task: 6428159](https://www.odoo.com/odoo/2328/tasks/6428159) https://github.com/odoo/o-spreadsheet/commit/ffa0759e3b [REF] plugins: Cell and table computed styles should be evaluation plugins [Task: 6428159](https://www.odoo.com/odoo/2328/tasks/6428159) https://github.com/odoo/o-spreadsheet/commit/14d6529e53 [IMP] model: enforce plugin type checking in registries [Task: 6428159](https://www.odoo.com/odoo/2328/tasks/6428159) https://github.com/odoo/o-spreadsheet/commit/7ba9c44037 [REF] plugins: HeaderVisibilityUI is now an evaluation one [Task: 6428159](https://www.odoo.com/odoo/2328/tasks/6428159) https://github.com/odoo/o-spreadsheet/commit/cfe91d0b79 [FIX] plugins: remove useless plugin registrations [Task: 6428159](https://www.odoo.com/odoo/2328/tasks/6428159) https://github.com/odoo/o-spreadsheet/commit/2dfd07c25f [FIX] module_math_test: correctly restore mock [Task: 6428159](https://www.odoo.com/odoo/2328/tasks/6428159) https://github.com/odoo/o-spreadsheet/commit/321b8c3ccc [IMP] model: cannot dispatch non-evaluation commands while handling evaluation commands [Task: 6428159](https://www.odoo.com/odoo/2328/tasks/6428159) https://github.com/odoo/o-spreadsheet/commit/b048c4ec57 [REF] plugins: split geo chart data in two [Task: 6428159](https://www.odoo.com/odoo/2328/tasks/6428159) https://github.com/odoo/o-spreadsheet/commit/76823227e2 [IMP] model: EvaluationPlugin can dispatch evaluation commands [Task: 6428159](https://www.odoo.com/odoo/2328/tasks/6428159) https://github.com/odoo/o-spreadsheet/commit/369d1dbdc2 [REF] plugins: CellIconPlugin is now a UI plugin [Task: 6428159](https://www.odoo.com/odoo/2328/tasks/6428159) https://github.com/odoo/o-spreadsheet/commit/309e941aff [REF] plugins: DynamicTranslate is now an evaluation plugin [Task: 6428159](https://www.odoo.com/odoo/2328/tasks/6428159) https://github.com/odoo/o-spreadsheet/commit/017bbd4ed1 [REF] plugins: evaluation does not depends on GridSelection anymore [Task: 6428159](https://www.odoo.com/odoo/2328/tasks/6428159) https://github.com/odoo/o-spreadsheet/commit/2605f043f6 [REF] plugins: PivotPresencePlugin is now an evaluation plugin [Task: 6428159](https://www.odoo.com/odoo/2328/tasks/6428159) https://github.com/odoo/o-spreadsheet/commit/ddb56fa69f [REF] model: introduce EvaluationGetters [Task: 6428159](https://www.odoo.com/odoo/2328/tasks/6428159) https://github.com/odoo/o-spreadsheet/commit/d5d47c5849 [REF] plugins: rename core view plugins to evaluation plugins [Task: 6428159](https://www.odoo.com/odoo/2328/tasks/6428159) https://github.com/odoo/o-spreadsheet/commit/54a7d3f27e [REF] getters: move core getters to getters file [Task: 6428159](https://www.odoo.com/odoo/2328/tasks/6428159) https://github.com/odoo/o-spreadsheet/commit/1e05bf468b [FIX] dashboard: fix carousel size in full screen charts [Task: 6498191](https://www.odoo.com/odoo/2328/tasks/6498191) https://github.com/odoo/o-spreadsheet/commit/4b793dc261 [IMP] Table side panel : added highlights to the table range [Task: 6008091](https://www.odoo.com/odoo/2328/tasks/6008091) https://github.com/odoo/o-spreadsheet/commit/ed86eee5ed [FIX] Table side panel: fix closing [Task: 6008091](https://www.odoo.com/odoo/2328/tasks/6008091) https://github.com/odoo/o-spreadsheet/commit/63d28e8776 [REF] owl3: remove env in arguments of some helpers [Task: 6522279](https://www.odoo.com/odoo/2328/tasks/6522279) https://github.com/odoo/o-spreadsheet/commit/4163cf9f5c [REF] zoom: move `withZoom` to the `ZoomStore` [Task: 6522279](https://www.odoo.com/odoo/2328/tasks/6522279) https://github.com/odoo/o-spreadsheet/commit/8ed60255f8 [FIX] figure: color of snap lines in dark mode [Task: 6515587](https://www.odoo.com/odoo/2328/tasks/6515587) https://github.com/odoo/o-spreadsheet/commit/54f3a5937e [FIX] pivot: unbounded ranges in the pivot side panel [Task: 6478220](https://www.odoo.com/odoo/2328/tasks/6478220) https://github.com/odoo/o-spreadsheet/commit/8e185c21ce [FIX] chart_menu: align chart menu items tag and style [Task: 6469005](https://www.odoo.com/odoo/2328/tasks/6469005) https://github.com/odoo/o-spreadsheet/commit/b4d373a724 [FIX] print: figure border wrong render [Task: 6458624](https://www.odoo.com/odoo/2328/tasks/6458624) https://github.com/odoo/o-spreadsheet/commit/4bc0222027 [FIX] chart: consistency in the background color for xlsx export [Task: 6507087](https://www.odoo.com/odoo/2328/tasks/6507087) https://github.com/odoo/o-spreadsheet/commit/bba2c34f66 [FIX] composer: crash when hovering a composer token [Task: 5153319](https://www.odoo.com/odoo/2328/tasks/5153319) https://github.com/odoo/o-spreadsheet/commit/48ac2d8d10 [FIX] evaluation: wrong dependencies invalidation with spread formulas [Task: 5103328](https://www.odoo.com/odoo/2328/tasks/5103328) https://github.com/odoo/o-spreadsheet/commit/d72cc0bc38 [FIX] chart_suggestion_engine: Update title if no header [Task: 6498667](https://www.odoo.com/odoo/2328/tasks/6498667) https://github.com/odoo/o-spreadsheet/commit/77d865f3c5 [FIX] chart suggestions: fix header for category and label [Task: 6498667](https://www.odoo.com/odoo/2328/tasks/6498667) https://github.com/odoo/o-spreadsheet/commit/4bc6b50d1b [IMP] chart_suggestion: reduces number of points for preview [Task: 6498667](https://www.odoo.com/odoo/2328/tasks/6498667) https://github.com/odoo/o-spreadsheet/commit/77ce125f23 [FIX] data_analysis_panel: help message for no chart suggestions [Task: 6498667](https://www.odoo.com/odoo/2328/tasks/6498667) https://github.com/odoo/o-spreadsheet/commit/f7b350e615 [FIX] session: fix part of the command squisher [Task: 6462247](https://www.odoo.com/odoo/2328/tasks/6462247) 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>
This update aligns Odoo Enterprise spreadsheet features with the latest spreadsheet engine changes. It improves reliability for spreadsheet comments, pivots, surveys, and sales field synchronization without introducing major user-facing changes.
Original PR description
See https://github.com/odoo/odoo/pull/285929
Polish bank account verification now handles batches where some partners are missing tax or bank details without causing an error. This keeps verification usable for mixed partner lists and avoids interruptions during routine checks.
Original PR description
When we check for multiple partners with some valid and some being incomplete (no vat or no bank account), a traceback is raised This was due to a bracket accessor, changed into a get in this commit. no-task Forward-Port-Of: odoo/odoo#285898 Forward-Port-Of: odoo/odoo#285631
This restores rules that prevent costs for re-invoiced products from being counted twice in project analytics when anglo-saxon accounting is used. It also brings back related test coverage and applies the logic per company, improving accuracy in multi-company workflows.
Original PR description
Restores the sale_project_stock_account module removed by 37b615f14305 ("[REM] sale_, project_stock_account: remove dead code"), which excludes re-invoiced products from the analytic lines generated…
Restores the sale_project_stock_account module removed by 37b615f14305
("[REM] sale_, project_stock_account: remove dead code"), which excludes
re-invoiced products from the analytic lines generated by stock moves
when anglo-saxon accounting is enabled, together with the test covering
it and the project_stock_account filter it extends.
That removal was justified by _account_analytic_entry_move() no longer
existing, concluding that analytic lines are not created from stock
moves anymore. That was true at the time: 08b62a4bbcc6 had dropped the
method along with the override of project_stock_account that filtered
the moves, and skipped the test guarding it in the same commit, so
removing the module turned nothing red. 1d510f2c2e05 then reintroduced
the analytic lines under _create_analytic_move, which is called whenever
moves are done, leaving the module wrongly missing.
_get_valid_moves_domain is restored on the new method, and with it the
exclusion of the re-invoiced products, whose cost is already carried by
the customer invoice under anglo-saxon accounting. 9a614c91ad7d has
since given project_stock_account a _create_analytic_move override that
skips the moves whose operation type has analytic costs disabled; the
restored filter is merged into that override instead of being added
beside it, and _get_valid_moves_domain keeps only the project condition,
the analytic-costs one now being applied to every move.
The exclusion is now decided per move, on the company of the move
itself: the removed code read the flag on the company of the user
processing the delivery, which ignores the company the delivery belongs
to. As the domain is evaluated for each move, the condition moves into
it instead of gating its construction.
TestAnalytics is un-skipped, as TestAnalyticsReinvoice extends it and
would otherwise inherit its skip. The other tests skipped to fast merge
the valuation refactoring are re-enabled separately.
The restored files predate 8a5b99545dfa, which renamed the product field
expense_policy to reinvoice_policy, so the domain and the test use the
new name.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#278698
Forward-Port-Of: odoo/odoo#275246This fix keeps a temporary accounting setting from being reused longer than intended during invoice and payment processing. It mainly improves reliability in automated tests and complex transaction flows, with little expected day-to-day impact for users.
Original PR description
This commits stop this context key to be leaked beyond necessary. In practice it's rarely an issue because the browser will do separate rpc calls with a clean context each time. It is particularily a problem while running some tests where everything happens in the transaction. task-none
This fix prevents a rare crash when Intrastat reporting logic is run in company access situations outside the standard user interface. It helps keep Danish, Lithuanian, and Swedish Intrastat processes stable for future customizations or edge-case setups.
Original PR description
Due to some trouble with tests, we found that in some cases, this function is called on the root company, and if the user does not have the access rights to read data from the company (users with system rights have them by default), it will cause a crash. This situation is not possible with the standard UI, but we fix it in case it becomes possible in a future version or customization. Forward-Port-Of: odoo/enterprise#129083 Forward-Port-Of: odoo/enterprise#128217
Opening the Sales Commissions report could fail because one percentage field was still available in the pivot report even though it could not be totaled. The field has been removed from the pivot measures so business users can load and analyze commission reports normally again.
Original PR description
Issue: `achieved_rate` lost its aggregator (set to aggregator=None) in 69e3827df02 so it wouldn't be summed/averaged in the list view, but it was still declared as a measure in the pivot view. Pivot always needs an aggregate function for its measures, so PivotModel's _getMeasureSpecs threw No aggregate function has been provided for the measure 'achieved_rate', crashing Sales > Reporting > Commissions on load. Solution: Remove achieved_rate as a pivot measure, consistent with it already being excluded from list-view totals. opw-6523870
Frontdesk kiosk check-ins no longer trigger an error when a visitor selects a host and the station has no email template configured. The fix ensures email notifications are only required or sent when the necessary template settings are available, keeping visitor registration smooth.
Original PR description
Currently, an error occurs when a visitor record is created through the kiosk in Frontdesk. **Steps to Reproduce;** - Install the `frontdesk` module. - Go to `Employees` and create a new employee or…
Currently, an error occurs when a visitor record is created through the kiosk in Frontdesk.
**Steps to Reproduce;**
- Install the `frontdesk` module.
- Go to `Employees` and create a new employee or open an existing one.
Set the employee's `email` and `work phone`.
- Go to `Frontdes` > `Stations` and create a station.
- Enable `Host Selection` and select that employee.
- Enable `Notify by email` and remove the `Frontdesk email template`.
- Open the `kiosk URL`, fill in the information, click `Browse All Hosts`,
select that `employee`, and click `Continue`.
- Error is logged in the terminal.
**Another case:**
- Clear the `email template`, disable `Notify by email`, and perform `step 6th`.
- The same error is raised.
`ValueError: Expected singleton: mail.template()`
After [recent commit], when a visitor record is created [1] through the kiosk and the selected
host has a work email while Notify by email is enabled on the station, the system attempts to
notify the host by email [2] . During this process, it renders the email body [3] and subject
using the station's mail template, which raises an error [4] when no mail template is configured.
Similarly, when Notify by email is disabled, if the selected host has no linked user record
but does have a work email, the notification falls back to email [5]. This also raises the same
error when no mail template is configured.
This commit ensure a mail template is required whenever Notify by email is enabled on a station.
For the fallback email notification (when the host has no user account), the system checks that
both a work email and a mail template are available before attempting to send the email,
since email notifications are not mandatory in this case.
[recent commit]: https://github.com/odoo/enterprise/pull/108297/changes
[1]: https://github.com/odoo/enterprise/blob/d025c1a6a87a90bdaead4195e5f996d058294604/frontdesk/controllers/main.py#L151-L162
[2]- https://github.com/odoo/enterprise/blob/d025c1a6a87a90bdaead4195e5f996d058294604/frontdesk/models/frontdesk_visitor.py#L112-L113
[3]- https://github.com/odoo/enterprise/blob/d025c1a6a87a90bdaead4195e5f996d058294604/frontdesk/models/frontdesk_visitor.py#L128-L131
[4]: https://github.com/odoo/odoo/blob/c76a3aedf523da6f751960d2b5dfbc0016416ef1/addons/mail/models/mail_render_mixin.py#L765
[5]- https://github.com/odoo/enterprise/blob/d025c1a6a87a90bdaead4195e5f996d058294604/frontdesk/models/frontdesk_visitor.py#L108-L111
sentry-7624715784
Forward-Port-Of: odoo/enterprise#125178Customers are now stopped from completing checkout when pricing rules unexpectedly make a cart total zero while zero-priced product sales are blocked. Instead of hanging at payment, they are sent back to the cart with a clear warning, reducing failed checkouts and support issues.
Original PR description
When 'Prevent Sale of Zero Priced Product' is enabled and a country-group pricelist prices a product at 0 once the customer's country becomes known during checkout, the cart total becomes 0. The 'free order' branch then validated the order at the payment step, which could hang and time out for a cart that is not actually sellable. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286025 Forward-Port-Of: odoo/odoo#284959
This fixes an issue in the Timesheets grid where clicking a day-based cell could get stuck showing the old value instead of cycling through the expected options. Users can now reliably update grid entries without refreshing or reselecting records, reducing friction during timesheet entry.
Original PR description
1. Open Timesheets > Configuration > Settings and set "Encoding Unit" to "Days", then save 2. Open Timesheets > Timesheets > All Timesheets and switch to the grid view 3. Click an empty cell -> it is selected and keeps displaying 0, and further clicks no longer cycle it through 0, 0.5 and 1 day The grid cell components memoise the value they display with `computed()`, but `GridCell` is a plain class whose `value` is mutated in place when the user edits the grid: reading it registers no dependency, and handing the same cell object back to the `cell` signal does not notify either. The memo is therefore never invalidated, and `FloatToggleGridCell.onChange` picks the next value of the range from that frozen value, so the toggle stops advancing as well. With this PR, the cell value is a signal, so every component deriving from it recomputes when the grid is edited. Task-6527559
This update prevents an internal invoice synchronization setting from remaining active longer than intended. It reduces the risk of incorrect behavior in accounting workflows, especially during automated tests or multi-step processing in the same session.
Original PR description
… of `skip_invoice_sync` This commits stop this context key to be leaked beyond necessary. In practice it's rarely an issue because the browser will do separate rpc calls with a clean context each time. It is particularily a problem while running some tests where everything happens in the transaction. task-none
This fix makes sure recent changes to internal reference records are saved before they are read by a direct database lookup. It prevents Odoo from using outdated configuration values in this specific workflow, improving reliability for module data handling.
Original PR description
Steps to Reproduce: - write on ir.model.data to modify noupdate. - _lookup_xmlids still returns the old noupdate value. Example: In [1]: imd = self.env['ir.model.data'] In [2]: xml_id =…
Steps to Reproduce:
- write on ir.model.data to modify noupdate.
- _lookup_xmlids still returns the old noupdate value.
Example:
In [1]: imd = self.env['ir.model.data']
In [2]: xml_id = self.env['ir.model.data'].search([], limit=1)
In [3]: imd._lookup_xmlids([xml_id.complete_name], self.env[xml_id.model])
Out[3]: [(18603, 'auth_signup', 'action_send_password_reset_instructions', 'ir.actions.server', 149, False, 149)]
In [4]: xml_id.write({'noupdate': not xml_id.noupdate})
Out[4]: True
In [5]: imd._lookup_xmlids([xml_id.complete_name], self.env[xml_id.model])
Out[5]: [(18603, 'auth_signup', 'action_send_password_reset_instructions', 'ir.actions.server', 149, False, 149)]
In [6]: imd.flush_model()
In [7]: imd._lookup_xmlids([xml_id.complete_name], self.env[xml_id.model])
Out[7]: [(18603, 'auth_signup', 'action_send_password_reset_instructions', 'ir.actions.server', 149, True, 149)]
Issue:
- _lookup_xmlids is returning values from ir.model.data executing an SQL query w/o flushing.
Fix:
- Add flushing in _lookup_xmlids.
Forward-Port-Of: odoo/odoo#262791Sales users without accounting permissions can now open invoices that use cash rounding when they are allowed to view the invoice. This prevents an unnecessary access error and keeps the sales invoicing workflow working smoothly.
Original PR description
**Behavior:** When a sales user without accounting access rights tries to view an invoice created from a sale order where a cash rounding is applied, an AccessError is raised. This occurs because…
**Behavior:** When a sales user without accounting access rights tries to view an invoice created from a sale order where a cash rounding is applied, an AccessError is raised. This occurs because loading the invoice view triggers `_compute_tax_totals()`, which then passes the invoice's `invoice_cash_rounding_id` to `_get_tax_totals_summary()`. Which then ends up failing when trying to access fields on the `cash_rounding` record due to missing accounting rights, even though the user is allowed to view the parent invoice. This is fixed by ensuring reading fields on `cash_rounding` during tax total computation bypasses the access check using `sudo()`, as the user already has legitimate access to the invoice itself. **Steps to reproduce:** - As an admin, enable cash rounding then create one. - Create an invoice and set the Cash Rounding Method - In debug mode, go to 'Set Default Values' in the debug dropdown and set Cash Rounding Method = your rounding for all users - Go to users, and ensures that Demo has no accounting rights but has sales user rights - As Demo, create a sale order, confirm it, then create the related invoice. - When trying to acces said invoice, you should get an Access Error opw-6379781 Forward-Port-Of: odoo/odoo#284212 Forward-Port-Of: odoo/odoo#278815
Users can now safely discard changes after reordering very long lists of order lines spread across multiple pages. This prevents an error that could interrupt quotation editing and improves reliability when working with large sales documents.
Original PR description
**Steps to reproduce:** - Create a quotation - Add order lines until reaching 200 (duplicating helps), save and ensure that the pager appeared (1-200/201) - Drag one of the lines with the handle to…
**Steps to reproduce:** - Create a quotation - Add order lines until reaching 200 (duplicating helps), save and ensure that the pager appeared (1-200/201) - Drag one of the lines with the handle to reorder them - Discard all changes (X shaped button) You will have an evaluation error **Behavior:** When loading a list of records exceeding the limit, only parts of the records are saved in `_cache`. When triggering a reordering of said list, all records need to be loaded including the ones on other pages: https://github.com/odoo/odoo/blob/d4eff7b14d37a9b59c95d304542a5a12629bc90b/addons/web/static/src/model/relational_model/static_list.js#L1139-L1149 `_getResIdsToLoad()` gets all Ids missing from the cache, these are then passed through `._createRecordDatapoint` and will then be stored in `_cache`. The issue is that the Datapoints are getting created with only `activeFields` as data, which in our case are `id` and `sequence` When discarding the changes `._checkValidity()`is called on each Datapoint: https://github.com/odoo/odoo/blob/d4eff7b14d37a9b59c95d304542a5a12629bc90b/addons/web/static/src/model/relational_model/record.js#L423-L429 And then `._isInvisible()` is called. This is where the issue happens, since only `sequence` and `id` are stored, when we try evaluate `combo_item_id`, which is the condition to see if sequence is invisible, `combo_item_id` is not found and we get an Evaluation Error. This commit prevents going into `._checkValidity()` by adding `this.isInEdition` to the check leading to it, requiring that the record is in 'edit' mode which is not the case for records created with `_createRecordDatapoint()` opw-6399024 Forward-Port-Of: odoo/odoo#281018
Point of Sale sessions can now close correctly when orders include both a lot-tracked product and a kit containing that product. The fix correctly totals quantities across multiple matching order lines, preventing an error that blocked session closing.
Original PR description
**Step to reproduce :** 1. Create Product A and enable lot tracking for it. 2. Create a Kit product and add Product A as one of its components. 3. Go to PoS and create orders using: - Product A - The…
**Step to reproduce :** 1. Create Product A and enable lot tracking for it. 2. Create a Kit product and add Product A as one of its components. 3. Go to PoS and create orders using: - Product A - The Kit product - A combination of Product A and the Kit product 4. Create three different orders with these combinations. 5. Try to close the PoS session. **Issue :** An error occurs when attempting to close the PoS session. The issue is in the pos_mrp module, specifically in the _get_lot_line_qty method. When accessing the following line: `lines_data[move.bom_line_id.bom_id.product_tmpl_id.product_variant_id.id]['order_lines'].qty` we expect order_lines to contain a single record. However, in this scenario, multiple order lines can be returned for the same product. As a result, accessing .qty directly on order_lines raises a singleton error. **Solution :** With this fix, we first retrieve the quantity from each order line and thensum the quantities together. This ensures that multiple matching order lines are handled correctly and prevents the singleton error when closing the PoS session. opw-6442765 Forward-Port-Of: odoo/odoo#285612 Forward-Port-Of: odoo/odoo#281622
Swiss payroll employee records will no longer log unnecessary history entries when pension mutation records are refreshed. This reduces chatter clutter, especially during frequent automated updates, making important employee history easier to review.
Original PR description
Calling `_create_or_update_snapshot` after writing on an employee recomputes `lpp_mutations`, deleting and recreating the linked records. Because `lpp_mutations` was tracked, every `write` on an employee generated unhelpful chatter entries, cluttering important history. This was especially noisy during frequent writes in hourly crons. Disable field tracking on `lpp_mutations` to improve chatter clarity and overall user experience. opw-6285407 --- Forward-Port-Of: odoo/enterprise#129628 Forward-Port-Of: odoo/enterprise#128033
This fix prevents the Belgian payroll Dimona button or badge from disappearing after employee records are autosaved. It ensures HR teams can reliably access the required Dimona action when managing employee onboarding and payroll compliance.
Original PR description
Steps to reproduce: - Create an employee, fill in name, CP, contract start date, wage. - Leave the form without saving manually (e.g. open another record). - Select the employee again: the Dimona button/badge is gone and stays gone regardless of further edits. l10n_be_needs_dimona_in and l10n_be_dimona_next_action are server-computed but readonly=False let autosave submit a stale value, permanently blocking the recompute. Drop the stray readonly=False on both and add a regression test. Task 6515877 Forward-Port-Of: odoo/enterprise#129731 Forward-Port-Of: odoo/enterprise#129648
This fixes an issue in the French PDP registration process where the system referenced outdated field names. The correction helps prevent registration failures after the related routing fields were renamed.
Original PR description
The fields have been renamed in routing_... --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285619
The Tax Excl./Tax Incl. toggle badge no longer shows an unwanted outline when users hover, click, or focus on it. This keeps sales, purchase, and accounting forms looking consistent and avoids a small visual distraction during order entry.
Original PR description
The "Tax Excl."/"Tax Incl." toggle badge showed an unwanted outline in two cases: - On real keyboard/click focus, Bootstrap draws its default focus ring. - On plain mouse hover, useNavigation adds a "focus" class. Also, sale.order and purchase.order views were never given the `tax_mode_badge` class, so the account.scss fix silently never applied to them at all. Forward-Port-Of: odoo/odoo#283798
Incoming vendor bills processed from email will no longer use the saved original email file as the main invoice attachment. This helps ensure users see the actual invoice document preview instead of a broken or irrelevant email copy when emails include embedded PDFs.
Original PR description
When an incoming mail server has the "Keep Original" option enabled, a copy of every incoming mail is stored as original_email.eml. Because it is not a document of the invoice, the system unattaches…
When an incoming mail server has the "Keep Original" option enabled, a copy of every incoming mail is stored as original_email.eml. Because it is not a document of the invoice, the system unattaches it, however it may still be used as main attachment in case no other PDF or image was attached to the message. Steps to reproduce: - Configure an incoming mail server with "Keep Original" enabled, using an alias pointing to a vendor bill journal. - Send a mail to that alias containing an xml embedding a PDF. - Open that bill Issue: The invoice's main attachment points to the .eml file. This occurs because it is set before the PDF is extracted from the xml. Then, when import extracts the PDF, it is added as attachment on the invoice, but we already have a main attachment that won't be overwritten. However, once a pdf or image is added as attachment, the system will show the (broken) preview. opw-6431726 Forward-Port-Of: odoo/odoo#285409 Forward-Port-Of: odoo/odoo#280318
This fix updates a Belgian payroll attendance test so it remains reliable when demo employee data changes the company's worker count. It helps avoid false payroll test failures while preserving confidence that payslip calculations continue to run correctly.
Original PR description
The FFE employer contribution rate depends on the company's current worker count. Additional demo employees installed on runbot can move the company across the applicable threshold and change the expected payslip amounts. This commit update the test expectations according to the computed worker count. [error-939674](https://runbot.odoo.com/odoo/error/939674) Forward-Port-Of: odoo/enterprise#130025 Forward-Port-Of: odoo/enterprise#126887
Customer-facing invoice pages no longer show the salesperson's city or phone number. This keeps invoice and sales order views consistent while reducing the risk of exposing personal employee information, such as home-office location details.
Original PR description
This change aligns the salesperson's information shown to customers on the invoice view with those shown on the sales order view. Now city and phone number are not shown and both views are consistent. This information can be personal information not supposed to be leaked to customers especially the salesperson's city in case of home office. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285845 Forward-Port-Of: odoo/odoo#278497
Uruguay electronic invoicing now uses the exchange rate saved on the original invoice instead of recalculating it later. This prevents credit notes or related documents from showing mismatched rates when currency rates are updated after an invoice is posted.
Original PR description
18.0 introduced an `invoice_currency_rate` field, storing the currency rate used for each invoice. Currently `_l10n_uy_edi_get_used_rate` uses the `currency.convert()` method using the date and company of the invoice. This is vulnerable to inaccuracy if the currency rates are changed after the invoice posting. For example, if an invoiceis posted and the currency rates are updated, the invoice will use the old rate, while `_l10n_uy_edi_get_used_rate` will return the new one. In the case of the customer in the related ticket, this caused their credit note reference currency rate to mismatch with the one on the invoice. This PR changes the `currency.convert()` call to fetching and inverting the `invoice_currency_rate` field. This ensures the returned value will match the one used for the invoice. opw-6456867 Forward-Port-Of: odoo/enterprise#129620 Forward-Port-Of: odoo/enterprise#128190
Incoming VoIP calls that time out and go to voicemail are now clearly marked as missed. This avoids confusing call messages and keeps call records accurate for users reviewing their communication history.
Original PR description
Steps to reproduce: - Call your softphone with your smartphone. - Let the smartphone ring forever. => At some point, you reach the voicemail and the softphone stops ringing but: - The softphone…
Steps to reproduce: - Call your softphone with your smartphone. - Let the smartphone ring forever. => At some point, you reach the voicemail and the softphone stops ringing but: - The softphone displays a weird message with emojis. - The call record stays "Trying to call" (and might *display* "Ended unexpectedly" in 19.2). This commit fixes those two issues by showing a proper "Call missed" message and switching the call record status to "Missed". This is done in 19.2 and not before... because the behavior before is even more problematic: - 19.1: the softphone keeps ringing and crash if you try to answer, that was mostly fixed thanks to [1] and this commit takes profit of those big ameliorations to fix the issue here. - 19.0: you do not even reach voicemail (it stops without saying anything). This was apparently fixed as a side-effect of [2], which we do not consider worth even partially backporting as not critical. [1]: https://github.com/odoo/enterprise/commit/942f32316ab02d8c739fe7fdd5ec2bdde472a68e [2]: https://github.com/odoo/enterprise/commit/d24d7f3406ca47e7ac529d69957b0ad481d553bf task-6453500 Forward-Port-Of: odoo/enterprise#128731 Forward-Port-Of: odoo/enterprise#127075
This fix ensures alerts in the Point of Sale restaurant appointment flow are dismissed after a table is assigned to a booking. It prevents lingering warning messages that could confuse staff during booking and table management.
Original PR description
Steps to reproduce: ==================== - In `pos_restaurant_appointment`, try to reassign a table to a booking. - An alert is shown. - Assign a table to the booking. Issue: ====== - The alert is not dismissed. Cause: ====== - In `pos_alert_plugin`, `dismiss` is updated instead of `_dismiss`. Fix: ==== - Update `_dismiss` instead of `dismiss`. task-6522926 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fix ensures mail records clean up temporary calculated data when a store is closed. It prevents memory from building up during long test runs, improving reliability and avoiding browser-session timeouts.
Original PR description
Before this commit, the mail files of WebSuite.test_unit_desktop take the heap from 82 MB to 1665 MB, read on the [MEMINFO] line each file logs after a forced major GC. Past 2 GB that GC stops…
Before this commit, the mail files of WebSuite.test_unit_desktop take the heap from 82 MB to 1665 MB, read on the [MEMINFO] line each file logs after a forced major GC. Past 2 GB that GC stops returning on runbot and the suite dies on "AssertionError: Script timeout exceeded". This happens because a record holds its computeds in a RecordScope that only the deletion of that record destroys, and a test deletes no record. The test teardown calls _runDisposeFns on the store, which stops what each record registered there and destroys the scope of the store alone, so every computed stays an observer of the signals it read. Message.richBody reads a signal of the module-level emojiLoader, so each message ever rendered keeps its store, its env and its app alive for the whole browser session. This commit registers the destruction of a record scope among the dispose functions of the store, so that the store teardown reaches the computeds of every record, as it already reaches the effect of every compute field. The same run then ends on 127 MB. https://runbot.odoo.com/odoo/error/946840
The salary simulation flow now keeps the employee's job information available when benefits are configured. This prevents an error that previously blocked users from validating a salary simulation from an employee record.
Original PR description
Steps to reproduce: - Go to an employee form. - Click on the salary simulation button. - Click on the configure benefits button. - UserError: "Missing required fields: Employee Job". Reason: `employee_job_id` was missing from the calculator form view XML, causing the field to be empty when validating the simulation. Solution: Add `employee_job_id` as an invisible field in the form view. Task-6497089
The Nilvera PDF button now appears only where relevant for Turkish companies, reducing confusion for other users. Invoicing users without administrator rights can now send, fetch, and download Nilvera e-invoices without access errors, and invoices with unknown status are refreshed immediately when requested.
Original PR description
## Description of the issue/feature this PR addresses: Two related Nilvera e-invoice issues affecting Turkish companies: - The "Fetch Nilvera PDF" button appeared for every company, not just Turkish…
## Description of the issue/feature this PR addresses:
Two related Nilvera e-invoice issues affecting Turkish companies:
- The "Fetch Nilvera PDF" button appeared for every company, not just Turkish ones.
- Sending/fetching e-invoices (or fetching the PDF) as a non-admin Invoicing user raised an
AccessError, because the company's Nilvera API key field is restricted to System/Settings users
and several call sites read it without `.sudo()`.
## Current behavior before PR:
- The PDF-fetch button shows on both the list view and form view of `account.move` regardless of
the company's country.
- An Invoicing-only user (no System/Settings access) gets an AccessError when sending/fetching
e-invoices or fetching the PDF, because `_get_nilvera_client` reads
`company.l10n_tr_nilvera_api_key` without `.sudo()`.
## Desired behavior after PR is merged:
- Both buttons are only visible for Turkish companies (the list-view button has no bound record, so
its gate is driven by a new `l10n_tr` session_info/JS context injection instead of a direct field
reference).
- Invoicing users can send/fetch e-invoices and fetch the PDF without hitting an AccessError.
## Things to add on forward-port
The `.sudo()` fix lives inside `_get_nilvera_client` itself (`l10n_tr_nilvera/lib/nilvera_client.py`),
so every caller that goes through it is already fixed automatically once this diff forward-ports.
Only call sites that read `company.l10n_tr_nilvera_api_key` **directly**, bypassing
`_get_nilvera_client`, still need their own `.sudo()`:
### 19.4
- [ ] Fix e-Dispatch/e-Receipt fetch gate-check access error (direct read of the API-key field,
sudo it the same way as `_l10n_tr_nilvera_company_get_documents` in this PR)
task-6328589
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#285360
Forward-Port-Of: odoo/odoo#274312Fixes an accounting issue where cost of goods sold could be overstated after a sale was delivered, returned, credited, and sold again. Credit notes are now included so earlier invoices and refunds properly offset each other, improving inventory cost accuracy.
Original PR description
**Steps to reproduce:** - create a storable product with a positive quantity a cost of 10 and average perpetual category - confirm a SO for 1 quantity, validate delivery - confirm invoice for 1 (COGS…
**Steps to reproduce:** - create a storable product with a positive quantity a cost of 10 and average perpetual category - confirm a SO for 1 quantity, validate delivery - confirm invoice for 1 (COGS should be 10) - return the delivery and validate - create a credit note from the invoice for 1 and confirm (COGS should be 10) - return the return and validate - change the standard price to 100 - create an invoice from the SO for 1 and confirm **Current behavior:** cogs are 190 **Expected behavior:** cogs should be 100 **Cause of the issue:** _get_posted_cogs_value doesn't take into account the credit notes (only the account moves with type 'out_invoice' are taken into account in the sum) https://github.com/odoo/odoo/blob/0824dc24665de6bfa805d540e756cdcb006edba6/addons/sale_stock/models/account_move.py#L185-L186 So in our case the first invoice and the credit note don't cancel out each other. The same goes for _get_cogs_qty (which returns the total cogs past + current), in the past cogs it doesn't take into account the quantities of the credit note. https://github.com/odoo/odoo/blob/0824dc24665de6bfa805d540e756cdcb006edba6/addons/sale_stock/models/account_move.py#L172-L174 So the quantity of the first invoice and the one of the credit note don't cancel out each other. As a result, the return value from _get_cogs_value() for the second invoice is : price unit = 100 returned by _get_cogs_price_unit() https://github.com/odoo/odoo/blob/0824dc24665de6bfa805d540e756cdcb006edba6/addons/stock_account/models/account_move_line.py#L68 which returned the standard price because the product has an average cost method https://github.com/odoo/odoo/blob/0824dc24665de6bfa805d540e756cdcb006edba6/addons/stock_account/models/stock_move.py#L275-L280 cogs_qty = 2 (instead of 1 if credit was taken into account as -1 in the sum) self._get_posted_cogs_value() = 10 (instead of 0 if credit note cogs were taken into account in the sum as -10) return value = (100 * 2 -10)/1 = 190 https://github.com/odoo/odoo/blob/0824dc24665de6bfa805d540e756cdcb006edba6/addons/stock_account/models/account_move_line.py#L75 **fix:** if we take into account the credit note the return value will be : (100 * 1 - 0)/1 = 100 the mechanism of the already posted cogs value is there for cases where we only delivered a part of the quantity and then delivered the rest, but in the case where we delivered and then returned (with credit notes) it shouldn't have an impact. Thus the idea to include the credit note so that it can cancel out the first invoice opw-6426111 Forward-Port-Of: odoo/odoo#284151 Forward-Port-Of: odoo/odoo#282893
Spreadsheet thumbnail previews now load correctly after a change in how file data is returned. This helps users recognize and select the right spreadsheet from the document selector without broken or missing previews.
Original PR description
Binary fields now return a POJO `{filename, content}` rather than a simple string, but the code to display spreadsheet thumbnails wasn't adapted.
Task: [6522764](https://www.odoo.com/web#id=6522764&cids=1&menu_id=4720&action=333&active_id=2328&model=project.task&view_type=form)Belgian payroll now calculates holiday pay regularization from the amounts already recovered during the year and the official attestation cap, instead of recalculating from the employee's current salary. This prevents past leave-related payroll values from changing after a salary update, making year-end adjustments more predictable and accurate.
Original PR description
Previously, holiday pay regularization was calculated using the current payslip's wage, causing past leave values to change whenever the salary was updated. Update `_get_holiday_pay_regularization`…
Previously, holiday pay regularization was calculated using the current payslip's wage, causing past leave values to change whenever the salary was updated.
Update `_get_holiday_pay_regularization` to compute the remaining balance directly from historical 90% recovered amounts (`HolPayRec`) and the attestation cap. This ensures the regularization stays fixed based on the wage at the time leave was taken.
During the year, paid leave days deduct 90% of the wage (HolPayRec). During the annual
regularization, this method calculates the adjustment needed to reach 100% of the wage
equivalent, capped by the total attestation amount (amount_to_recover).
Variables:
- recovered_amount: Total 90% leave deductions (HolPayRec) already applied.
- amount_to_recover: Total holiday pay cap from previous year's attestations.
- total_100_pct_wage: 100% wage equivalent ((recovered_amount / 9.0) * 10.0).
- max_recoverable: Upper limit allowed to recover, min(total_100_pct_wage, amount_to_recover).
- regularization_amount: Difference between max_recoverable and recovered_amount.
Formula:
regularization_amount = min((recovered_amount / 9.0) * 10.0, amount_to_recover) - recovered_amount
Return value = -regularization_amount
Examples:
1. Negative Return Value (Deduction / Further Recovery):
- amount_to_recover = €1,000
- recovered_amount = €450 (90%)
- total_100_pct_wage = (450 / 9) * 10 = €500
- max_recoverable = min(500, 1000) = €500
- regularization_amount = 500 - 450 = €50
- Return: -€50 (Deducts remaining 10% from employee).
2. Positive Return Value (Refund / Over-recovery Correction):
- amount_to_recover = €300 (Low attestation cap)
- recovered_amount = €450 (Already recovered throughout the year)
- total_100_pct_wage = (450 / 9) * 10 = €500
- max_recoverable = min(500, 300) = €300
- regularization_amount = 300 - 450 = -€150
- Return: +€150 (Refunds €150 to employee because recovery exceeded the attestation cap).
Returns:
tuple: (-regularization_amount, explanation_info)
Task : 6453625Belgian payroll now counts the employee's final working day when deciding whether a contract meets the short-term employment threshold. This prevents sick leave from being incorrectly treated as unpaid for employees whose contract spans exactly three months.
Original PR description
Steps: - Create a short term employee, contract spanning exactly 3 months - Create a sick leave for the employee - Sick leave is unpaid Cause: - Currently the threshold for determining short term employees was fixed at 3 months exactly, meaning that excludes the last working day of the employee Solution: - Short term employee threshold is now adjusted to take into consideration the last working day of the employee in its computation. Task: 6515351
This fixes a timing issue where the reply box could stay open because suggestion popups reopened after being dismissed. Users get more reliable keyboard behavior when closing replies or popups in the Mail app, especially under slower server conditions.
Original PR description
Two independent causes made "reply: discard on pressing escape" red, one commit each. "[FIX] mail: wait for the mention suggestions before Escape" is the one that fixes the reported failure, and it holds on every branch: the test presses Escape while the mention fetch is in flight, and the suggestions arriving from the server re-open the list that Escape closed, so the re-opened list takes the second Escape and the reply is never discarded. The test now waits for the fetched suggestions before pressing Escape. "[FIX] mail: keep the suggestion list closed on a re-render" backports "[FIX] mail: keep composer suggestion list closed on unrelated re-render", which entered at 19.0 and never came down. Here NavigableList is re-opened on every patch, so opening the emoji picker after Escape brings the dismissed list back, and it then steals the Escape meant for the picker. https://runbot.odoo.com/odoo/error/946314 Forward-Port-Of: odoo/odoo#286041 Forward-Port-Of: odoo/odoo#284725
Fixed an issue where creating a new group in a grouped list view could cause an error when totals or aggregates were shown. This helps users continue data entry smoothly without interruptions in views such as CRM lists.
Original PR description
Adding a new group on a grouped list view with aggregates gives a traceback. This comes from `getFieldCurrencies` and `computeAggregates` which didn't guard for group with no currency aggregates (like a newly created group). Steps to reproduce: - open a list view (CRM) - group by a m2o (Contact) - click on 'Add a Contact' - press Enter => Traceback Forward-Port-Of: odoo/odoo#285920 Forward-Port-Of: odoo/odoo#285325
Users will no longer see an unnecessary warning notification when a pasted internal link cannot generate a preview, such as when the URL contains a typo. The issue is still recorded in the browser console, reducing distraction while keeping diagnostic information available.
Original PR description
When an internal link preview is missing, a notification is displayed to inform the user that the link is likely wrong. This commit logs this information in the console instead of showing it as a notification. Steps to reproduce: - Go to a To-do note - Create a link - Paste the current URL but introduce a typo in "to-do" => A notification was displayed. task-6317849
The website shop builder now shows a brush icon for the products design button instead of a less clear design services icon. This restores a more familiar visual cue, helping users recognize the design action more easily.
Original PR description
The products design button was previously `fa-paint-brush`. It was replaced by the `design_services` Material Symbols instead of the more similar `brush`. This commit changes it back to a brush. task-6377407
This fixes an issue where manufacturing-related accounting entries could be created in an unpredictable order during subcontracting receipt processing. The change makes results more consistent and helps avoid occasional test or reporting inconsistencies caused by identical dates and document names.
Original PR description
The search order on account move line depends on date, move name and id. This search result order can be non deterministic because, when creating account move line from stock valuation, it depends on…
The search order on account move line depends on date, move name and id. This search result order can be non deterministic because, when creating account move line from stock valuation, it depends on the order from a set, but sets are unordered. **Step to reproduce** Run [test_subcontracting_purchase_bill](https://github.com/odoo/odoo/blob/13b2781978b0edad0df0800404276919b767e32b/addons/mrp_subcontracting_purchase/tests/test_mrp_subcontracting_purchase.py#L268) in: Single app, community, with demo data. **Observation** * The search: When doing the search since we didn't specify any order, the search from account.move.line will ordered by: https://github.com/odoo/odoo/blob/3dd41395e2e4205fa477eb474d4a4dba0a976154/addons/account/models/account_move_line.py#L23 https://github.com/odoo/odoo/blob/3dd41395e2e4205fa477eb474d4a4dba0a976154/addons/account/models/account_move_line.py#L1664 Since, for the components the date and move name are the same it will only depend on the aml ids: * `Account.move.line` creation: When it validate the receipt (`button_validate`) https://github.com/odoo/odoo/blob/869c750f978b1b00a4a04bd61226f0e20d2e7729/addons/mrp_subcontracting_purchase/tests/test_mrp_subcontracting_purchase.py#L296 It will mark as done the picking (`_action_done`) and the productions (`button_mark_done`) linked to this picking. https://github.com/odoo/odoo/blob/869c750f978b1b00a4a04bd61226f0e20d2e7729/addons/stock/models/stock_picking.py#L1429 https://github.com/odoo/odoo/blob/869c750f978b1b00a4a04bd61226f0e20d2e7729/addons/mrp_subcontracting/models/stock_picking.py#L49 Modify the inventory accordingly (`_post_inventory`) https://github.com/odoo/odoo/blob/869c750f978b1b00a4a04bd61226f0e20d2e7729/addons/mrp/models/mrp_production.py#L2231 while inside of `_post_inventory`, it will process all the production moves, for this it will divided them in set to process them by batch: https://github.com/odoo/odoo/blob/f0e58b9324af18d0cf0264aec2886d098e997f03/addons/mrp/models/mrp_production.py#L1904-L1911 From this set, it will create the `account.move.line`: It retrieve the actual stock move with the browse, and call `_action_done`, from where the stock valuation layer will create the `account.move.line`. https://github.com/odoo/odoo/blob/f0e58b9324af18d0cf0264aec2886d098e997f03/addons/mrp/models/mrp_production.py#L1913 https://github.com/odoo/odoo/blob/f0e58b9324af18d0cf0264aec2886d098e997f03/addons/stock_account/models/stock_move.py#L187 The issue arise because a set read order is non deterministic. runbot-939794 Forward-Port-Of: odoo/odoo#279396
Self-order payment notifications no longer include full order details when sent through live updates. This reduces unnecessary data sharing while keeping order status updates working for customers and staff.
Original PR description
Remove the order data from the websocket notification. Forward-Port-Of: odoo/odoo#285517 Forward-Port-Of: odoo/odoo#284631
Fixed an issue that could prevent users from opening WhatsApp Business account settings after switching Odoo to another language, such as French. The page now relies on a language-independent identifier, so translated labels no longer cause an error.
Original PR description
Currently, an error occurs when a user tries to view the WhatsApp Business account. **Steps to Reproduce:** - Install the `whatsapp_oauth` module. - Go to `Settings` > `Languages` and add `French…
Currently, an error occurs when a user tries to view the WhatsApp Business account. **Steps to Reproduce:** - Install the `whatsapp_oauth` module. - Go to `Settings` > `Languages` and add `French (BE)`, then `switch to it`. - Go to `WhatsApp` > `Configuration` > `WhatsApp Business Accounts (Comptes Whatsapp Business)`. `ValueError: L'élément '<xpath expr="//div[contains(normalize-space(.), 'Receiving Messages')]">' ne peut être localisé dans la vue parente` When the user changes the language, the text in the view is translated [1]. Since the WhatsApp account view tries to locate the div using the plain text Receiving Messages [2]. Since the text has been translated in the parent view, the XPath can no longer locate the element and raise the error. This commit ensures that the XPath uses the name attribute to identify the element, which is language-independent. We cannot use the class attribute because the same class is used by other div elements. [1]- https://github.com/odoo/enterprise/blob/a3db72899cb97612505aebbd5450aeb65205db73/whatsapp/views/whatsapp_account_views.xml#L81-L84 [2]- https://github.com/odoo/enterprise/blob/a3db72899cb97612505aebbd5450aeb65205db73/whatsapp_oauth/views/whatsapp_account_views.xml#L61-L63 sentry-7534862409 Forward-Port-Of: odoo/enterprise#130003
This fix removes Italian eInvoicing fields that were mistakenly shown in the Point of Sale partner form. It keeps the Italian PoS setup aligned with its supported scope, avoiding confusing or unavailable invoicing options for users.
Original PR description
The PoS has a dedicated "simplified" partner form view since 19.2. We had to fix in stable the fields that were missing (typically needed for eInvoicing) in the simplified view by completely overriding the simplified view with the old one. In master, we added the fields back to the simplified view. When doing so, we mistakenly re-added Italian eInvoice fields to the l10n_it_pos module, while this one is not supporting eInvoicing in PoS, only printers, and not even depending on l10n_it_edi that holds the field. This commit removes the extension of the simplified view that was not necessary. Note: added in the same version, no need to handle migration. Related: https://github.com/odoo/enterprise/pull/119316 runbot-946594
Planning shifts will now only show missing-role warnings for human resources, not material resources. This reduces unnecessary alerts when shifts include equipment or other non-human resources that are still valid for the work.
Original PR description
Currently, the warning stating that the resources selected on the shift don't have the required role might be triggered too easily. Human and material resources will likely have different roles due to their different nature. However, a shift can only have a single role, which will usually be the one required for the human resources, while the shift itself may be assigned to a mix of human and material resources. As a result, the warning will often be triggered for material resources even though they are valid for the shift, which could create noise for users. With this PR, the warning is only triggered for human resources Task-6467213
Payroll users can now remove or change payslip period dates without triggering an unexpected error. This keeps payslip creation and editing stable when employee contract dates are present.
Original PR description
Currently, an error occurs when the user removes the payslip period. **Steps to Reproduce:** - Install the `hr_payroll` module. - Go to `Employees` and create an `employee`, or use an existing one. -…
Currently, an error occurs when the user removes the payslip period. **Steps to Reproduce:** - Install the `hr_payroll` module. - Go to `Employees` and create an `employee`, or use an existing one. - Make sure the `employee's version` has a `contract start date`. - Go to `Payroll` > `Payslips` > `Payslips` and create a payslip. - Select that `employee` on the payslip, then remove the `payslip start date`. `TypeError: '<=' not supported between instances of 'datetime.date' and 'bool'` After the [recent commit], which computes the version from the payslip period without allowing it to be overridden, when the user selects an employee whose version has a contract start date, it checks whether the version overlaps with the payslip period [1]. However, since the payslip dates have not yet been set, it raises an error. This commit ensures that the check for the version overlapping with the payslip period is skipped if the payslip does not have both a start and end date. It also makes the method depend on date_to, because if the user changes the payslip end date, it should recheck whether the version overlaps with the payslip period. [recent commit]: https://github.com/odoo/enterprise/commit/569ce2af32477d410b79e98ca72729385042619b [1]- https://github.com/odoo/enterprise/blob/8a66d7beabe6f9b28000ef12725f3a9937d5d1ee/hr_payroll/models/hr_payslip.py#L1716-L1725 sentry-7632216317 Forward-Port-Of: odoo/enterprise#126515
This update registers the Greek e-invoicing module with the translation system. It ensures the module can receive and manage translations properly, improving localization support for Greek users.
Original PR description
Commit https://github.com/odoo/odoo/commit/45bd522dde7a67194e14a40d66944a2e34d1f79d introudced a new module without it's related `weblate.json` entry. This commit fixes this omission. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285570
This fixes a subcontracting receipt issue where partially received items could be incorrectly split into backorders, causing non-subcontracted products to remain fully pending. The added regression coverage helps ensure mixed receipts with subcontracted and regular products are processed consistently.
Original PR description
### Steps to reproduce: - Create a subcontracted product P1 - Create a storable product P2 - Buy 5 units of both products from your subcontractor - On the receipt set both moves quantity to 2 Units -…
### Steps to reproduce: - Create a subcontracted product P1 - Create a storable product P2 - Buy 5 units of both products from your subcontractor - On the receipt set both moves quantity to 2 Units - Validate the receipt and create a backorder #### > Only the subcontracted move has been kept on the receipt and a backorder was created for 3 units of P1 and 5 of P2. ### Cause of the issue: Setting the quantity of the subcontracted move will automatically record the quantities on the subcontracted MO: https://github.com/odoo/odoo/blob/9440ff9064c77af0159a427de8f5e5721aec0de5/addons/mrp_subcontracting/models/stock_move.py#L83 https://github.com/odoo/odoo/blob/9440ff9064c77af0159a427de8f5e5721aec0de5/addons/mrp_subcontracting/models/stock_move.py#L123 https://github.com/odoo/odoo/blob/9440ff9064c77af0159a427de8f5e5721aec0de5/addons/mrp_subcontracting/models/mrp_production.py#L91 However, the `_update_finished_move` method adds and update the related subcontracted move lines marking them as *picked* to adapt the related reservation: https://github.com/odoo/odoo/blob/9440ff9064c77af0159a427de8f5e5721aec0de5/addons/mrp_subcontracting/models/mrp_production.py#L118-L164 This is problematic since picking a move line will also pick the move: https://github.com/odoo/odoo/blob/9440ff9064c77af0159a427de8f5e5721aec0de5/addons/stock/models/stock_move.py#L261-L267 And only picked moves are considered to be processed at picking validation. ### Note: The exact same issue had already been fixed in 17.0: db8b33ebb9fe23507bcba30b12741e4d688ae549 However, the fix had an issue concerning the barcode behavior as it removed the picked computation for subcontracted moves which made hybrid pickings such as the above one (with one subcontracted and one non-subcontracted move) impossible to process in the barcode app. As such, the fix and test where reverted in cf2d18c92bee55ef79db1a338e9baf12f258ee5b The present commit provides an alternative fix of the original issue keeping subcontracted moves unpicked by quantity changes without affecting the picked computation of subcontracted moves (e.g. adding a picked move line on a subcontracted move will still pick that move). Enterprise: https://github.com/odoo/enterprise/pull/123884 opw-6330584 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285614 Forward-Port-Of: odoo/odoo#275304
The Point of Sale flow now hides quotations that have already been settled, so staff cannot accidentally select and settle the same quotation again. This helps avoid duplicate processing and reduces correction work for sales teams.
Original PR description
Once a quotation is settled, opening the quotation list should not allow selecting it again. This commits updates the domain to prevent it. task-6479356 Forward-Port-Of: odoo/odoo#284768
This fix prevents the guided tour feature from crashing when a tour that was previously started is no longer available in the database. Users, including free trial users, should now see the tour handled gracefully instead of encountering an error.
Original PR description
get_tour_json_by_name returned an empty array instead of False when no tour matched. TourService.getTour then skipped its `!tour` guard and crashed reading `tour.steps.length` on that string. Issue spotted on free trials Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286059
This update makes an internal automated test for the web reference field run consistently, even when there is a small network delay. It helps reduce false failures in Odoo's validation pipeline without changing customer-facing behavior.
Original PR description
The test is non-deterministic and fails with the runbot error:
found 0 elements instead of 1:
0 matching ".ui-autocomplete .ui-menu-item:nth-child(2)"
if there is even a 100ms network delay. clear() dispatches input events, but without flushing the timers, the dropdown state at the time of click(".o_field_reference input") can be out of sync causing no menu items to render and failing the test.
This change makes the sequence deterministic without changing the assertions:
1. runAllTimers() clears the timers and allows the clear of the input to fully go through.
2. click(".o_form_view") unfocus the input so the next click of the input refocuses and triggers the menu opening.
3. checking contains on the dropdown children ensures the menu items can render before click.
runbot error: 940222
Forward-Port-Of: odoo/odoo#286055Fixes an issue where expanding a newly created Calendar event dialog opened a blank form instead of the event just created. This prevents duplicate events from being created for the same time slot and makes quick event creation more reliable.
Original PR description
Problem: In Calendar, dragging a slot opens the quick create dialog. Typing a subject and clicking the expand button in the dialog header creates the event, but the form that opens is empty, and…
Problem: In Calendar, dragging a slot opens the quick create dialog. Typing a subject and clicking the expand button in the dialog header creates the event, but the form that opens is empty, and saving it creates a second event for the same slot. Cause: `FormViewDialog` stores the id of the record it saved in `currentResId`, which `onExpand` passes as `res_id`. `saveRecord` sets it only in the branch that runs when no `onRecordSave` prop is given. `AttendeeCalendarController` passes one since 30478fe855cd (odoo/odoo#239435), so `currentResId` stays false and the action opens a new record. Solution: Set `currentResId` in the shared branch of `saveRecord`. It is private to `FormViewDialog`, so a consumer passing `onRecordSave` cannot set it. Steps to reproduce: - Open Calendar. - Drag a slot in the week view to open the quick create dialog. - Type a meeting subject. - Click the expand button in the dialog header. - Observe that the form opens on a new record while the event is created. Ticket [link](https://www.odoo.com/odoo/project/49/tasks/6476930) opw-6476930 Forward-Port-Of: odoo/odoo#285899
This fixes a dependency issue in the Indian stock localization so related stock and accounting data is available when the app is tested or installed on its own. It helps prevent broken screens in e-waybill stock workflows and improves installation reliability without changing user-facing features.
Original PR description
The view 'l10n_in_ewaybill_stock.view_picking_form_inherit_ewaybill' is broken in single-app tests because it depends on stock.picking:country_code. That field is provided by module 'stock_account' through auto_install relationship. 'stock_account' auto_installs with 'stock' and 'account' installed. This condition exists on stable so it's safe to add this dependency. The dependency is added to l10n_in_stock because it seemed like the logical place where 'account' and 'stock' functionality comes together. [l10n_in_ewaybill_stock] ──[depends]──> [l10n_in_stock] [l10n_in_stock] ──[depends]──> [stock] [l10n_in_stock] ──[depends]──> [l10n_in] ──[depends]──> [account_tax_python] ──[depends]──> [account] REF Runbot: https://runbot.odoo.com/odoo/error/945482 Forward-Port-Of: odoo/odoo#284990
This fixes an issue where applying a color to a selected part of formatted text could color extra nearby text by mistake. Users can now apply text colors more precisely, avoiding unwanted formatting in website or content editing.
Original PR description
Problem: When applying color on a selection that spans across partially selected inline elements (e.g. `<p><b>a[b</b>c]d</p>`), container elements whose contents are not fully selected (such as…
Problem: When applying color on a selection that spans across partially selected inline elements (e.g. `<p><b>a[b</b>c]d</p>`), container elements whose contents are not fully selected (such as `<b>`) were included in `targetedNodes`. This caused improper color formatting/nesting on partially selected elements. Cause: In `ColorPlugin._applyColor()`, `targetedNodes` were filtered by checking `isNodeEditable(node)` and `nodeName !== "T"`, but did not check whether the contents of `node` were fully selected (`areNodeContentsFullySelected(node)`). As a result, partially selected ancestor elements were included in `targetedNodes`. Solution: Filter `targetedNodes` in `_applyColor()` using `this.dependencies.selection.areNodeContentsFullySelected(node)` to ensure only fully selected nodes are targeted when applying colors. Steps to reproduce: 1. Open html_editor. 2. Insert content: `<p><b>ab</b>cd</p>`. 3. Select `b` inside `<b>` and `c` inside `<p>` (`<p><b>a[b</b>c]d</p>`). 4. Apply text color (e.g. red). 5. Observe "ab" and "c" was colored instead of just "b" and "c". task-6456443 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285658 Forward-Port-Of: odoo/odoo#281462
Mexican CFDI invoice XML files now use the customer or user language for unit of measure labels when invoices are sent in bulk. This prevents English labels from appearing unexpectedly in Spanish-language invoices, improving consistency and compliance of generated documents.
Original PR description
### Issue before this commit: When a CFDI invoice was sent through a mass action (Send & Print executed by OdooBot), the unit of measure in the generated CFDI appeared in English instead of the…
### Issue before this commit: When a CFDI invoice was sent through a mass action (Send & Print executed by OdooBot), the unit of measure in the generated CFDI appeared in English instead of the configured language (e.g. Spanish. ### Steps to reproduce the issue: 1.Download Accounting, Contacts and l10n_mx 2. Switch to Spanish (MX) language 3. Set the language of "Inmoviliaria CVA" and "XENON INDUSTRIAL ARTICLES" to Spanish (MX) 4. In contacts select Archived in filters and switch OdooBot language to Spanish (MX) 5. Create and confirm two invoices in the database, one for each customer but don't send these invoices 6. Go to the list view and select these two invoices, and click on "Send and print" and select CFDI 7. Check any of the XML files generated in any of the invoices (in the CFDI tab of the invoice) 8. See that the UoM in the XML file, will be set in english rather than Spanish (MX) ### Cause of the issue: The context under which the batch action runs does not contain the lang key. As a result, translated fields (such as product_uom_id.name) were read in the source language (English) instead of the executing user's language, because nothing in the CFDI generation chain explicitly forced the correct lang into the context. ### Reason to introduce the fix: A CFDI must always report translated fields in the correct language. The fix ensures the invoice is read with the executing user's language when the context doesn't already specify one, so translated fields are consistently correct across both flows. opw-6399860 Forward-Port-Of: odoo/enterprise#129916 Forward-Port-Of: odoo/enterprise#125698
Fixed the Turkish reports journal form so the return from sales account appears in the correct place with the right label. This prevents confusion when users review or configure journal accounts.
Original PR description
The journal form renders `default_account_id` as six standalone labels followed by two `nolabel="1"` fields, one for bank, cash and credit journals and one for sale, purchase and general ones. The xpath matched the first of those two fields, so the return from sales account was inserted between them. Its own label then landed in the middle of the label run, shifting the group grid: both labels rendered side by side with their values underneath, each next to the wrong caption. Anchor on the second field instead, so the new field follows the whole label and field run. Task-6438412 Forward-Port-Of: odoo/enterprise#129532 Forward-Port-Of: odoo/enterprise#128083
Updating suggested products could fail when an unpublished product belonged to an eCommerce category. This fix prevents the error by safely handling cases where no published products are available, allowing staff to update suggestions without interruption.
Original PR description
Currently, an error occurs when the user tries to update suggested products. **Steps to Reproduce:** - Install the `website_sale` module. - Go to `Settings` and enable `Automate suggested products`…
Currently, an error occurs when the user tries to update suggested products.
**Steps to Reproduce:**
- Install the `website_sale` module.
- Go to `Settings` and enable `Automate suggested products` under the `eCommerce` section.
- Go to `Website` > `eCommerce` > `Products` > `Products`.
- Create a `product` and, in the `eCommerce` tab, add a `category`.
- Make sure the `product` is `not published`.
- On the `product`, click the `gear icon` and select `Update suggested products`.
`ValueError: TypeError('unsupported operand types in: product.template() | None') while evaluating 'records.action_update_suggested_products()'`
When the user updates suggested products, the system updates the product's suggested
products - optional, accessory, and alternative products [1]. While updating the alternative
products [2], the system tries to find products based on the categories and attributes shared
with the current product [3]. When retrieving products from the current product's category,
it gets None [4] because the products linked to that category are unpublished and are
therefore excluded by the domain [5]. Later, using this None value raise the error.
This commit ensures that when accessing a missing key in the category dictionary, then it falls
back to an empty product recordset.
[1]: https://github.com/odoo/odoo/blob/21e3310a3eba2ce915b33cf10ee4c14bdda7aad4/addons/website_sale/models/product_template.py#L346
[2]: https://github.com/odoo/odoo/blob/21e3310a3eba2ce915b33cf10ee4c14bdda7aad4/addons/website_sale/models/product_template.py#L384-L386
[3]: https://github.com/odoo/odoo/blob/21e3310a3eba2ce915b33cf10ee4c14bdda7aad4/addons/website_sale/models/product_template.py#L471-L483
[4]- https://github.com/odoo/odoo/blob/21e3310a3eba2ce915b33cf10ee4c14bdda7aad4/addons/website_sale/models/product_template.py#L482
[5]- https://github.com/odoo/odoo/blob/21e3310a3eba2ce915b33cf10ee4c14bdda7aad4/addons/website_sale/models/product_template.py#L445-L456
sentry-7660509183
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#281487This fix makes an internal website performance test consistent during parallel test runs. It prevents unrelated demo data from changing the test conditions, helping keep automated validation reliable without affecting normal users.
Original PR description
# Before this commit: The image controller performance test expects the admin partner to be unpublished. In parallel test runs, the website_partner demo data publishes the admin partner, causing the…
# Before this commit:
The image controller performance test expects the admin partner to be
unpublished. In parallel test runs, the website_partner demo data
publishes the admin partner, causing the test to follow a different
code path and fail.
However, during parallel test execution, the website_partner module
installs its demo data, which updates the admin partner:
```
<record id="base.partner_admin" model="res.partner">
<field name="is_published">True</field>
</record>
```
As a result, user_admin.website_published becomes True.
# After this commit:
The test explicitly restores the required precondition by setting the
admin partner's is_published value to False before executing the
performance check.
As a result, the image controller always follows the expected
"unpublished" code path, making the test deterministic regardless of
whether website_partner or any other module with demo data has already
been installed during parallel testing.
Runbot-241102
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#278550This fix prevents an error when loading sample work order data after a specific working schedule has been deleted. The system now uses a safe default schedule instead, helping users test or set up Shop Floor without interruption.
Original PR description
Currently, an error occurs when loading the sample data in the Shop Floor. **Steps to Reproduce:** - Install the `mrp_workorder` module. - Go to `Employees` > `Configuration` > `Working Schedules`. -…
Currently, an error occurs when loading the sample data in the Shop Floor. **Steps to Reproduce:** - Install the `mrp_workorder` module. - Go to `Employees` > `Configuration` > `Working Schedules`. - Delete the `Work Center 40 hours/week` record. - Go to `Settings` > `Users & Companies` > `Groups`. - Open the `Manage Work Order Operation` group and add the `Administrator` to the `users` list. - Open the `Shop Floor`. If the `Activate your Work Center` dialog appears, click it and then click `Configure Later`. - Click `Load Samples`. `ValueError: External ID not found in the system: mrp.mrp_workcenter_calendar` After the [recent commit], the sample work center uses the `Work Center 40 hours/week` working schedule instead of `Standard 40 hours/week`. As a result, if the `Work Center 40 hours/week` record is deleted, loading the sample data raises the error [1]. This commit ensures that when the Work Center 40 hours/week calendar is not available, it falls back to `Standard 40 hours/week`, restoring the previous behavior [2]. This fallback is required because `resource_calendar_id` is mandatory from the view perspective, even though it is not required at the model level. If it is left empty, the form displays a missing required field. The `Standard 40 hours/week` calendar is always available because it is linked to the main company [3] and its `resource_calendar_id` field uses `ondelete='restrict'` [4], preventing it from being deleted. [recent commit]: https://github.com/odoo/enterprise/commit/336d721f7b353473fe5e07c29ce14ed77a88fb98 [1]- https://github.com/odoo/enterprise/blob/c0045ec3cf94650d66192a4ca3e0dc3c17daa5bd/mrp_workorder/models/mrp_production.py#L213-L216 [2]- https://github.com/odoo/enterprise/blob/51c1e74e90e510d59aad78820e2c29e821ba2854/mrp_workorder/models/mrp_production.py#L214-L217 [3]: https://github.com/odoo/odoo/blob/4c4219a7d9d51f703b15e83ab755faf1f2c8a71d/addons/resource/data/resource_data.xml#L10-L12 [4]: https://github.com/odoo/odoo/blob/4c4219a7d9d51f703b15e83ab755faf1f2c8a71d/addons/resource/models/res_company.py#L12-L13 sentry-7651161729 Forward-Port-Of: odoo/enterprise#126859
Fixes an error that could block users when creating a second time off accrual allocation with the same plan. This improves reliability for HR teams managing employee leave balances, especially in payroll configurations that trigger accrual recalculations.
Original PR description
**Steps to Reproduce:** - Install the Time Off app and Belgian Payroll (l10n_be_hr_payroll). - Create and validate an accrual allocation for currently logged-in user with: No end date Any start date…
**Steps to Reproduce:** - Install the Time Off app and Belgian Payroll (l10n_be_hr_payroll). - Create and validate an accrual allocation for currently logged-in user with: No end date Any start date An accrual plan configured with a carry-over milestone Any Time Off Type - Create another allocation for the same employee, using the same accrual plan and same Time Off Type, but with a different start date that is not in the future. - Select the accrual plan. The error is raised immediately during the onchange. **Issue:** - When the accrual allocation onchange computes the accrued balance, a temporary allocation is used internally to simulate the accrual computation. - This temporary record is discarded after the computation. - The discarded temporary record can remain pending for computed field recomputation. - When the onchange later triggers recomputation, the stale temporary NewId can cause: `KeyError: <NewId origin=18>` **Root Cause:** - Temporary allocations created with 'new(origin=allocation)' can add computed fields to `env.transaction.tocompute`. - `invalidate_recordset()` clears the temporary record's cache but does not remove the `NewId` from the pending recomputation queue. - Since the temporary record has no database row to recompute from, the NewId can later be picked up during recomputation. - This can lead to a KeyError when the framework tries to access cached data for the discarded temporary record. **Solution:** - Properly discard temporary allocations after the accrual simulation. - In addition to invalidating the cache, remove the temporary NewId from `env.transaction.tocompute` using `remove_to_compute()`. - Use this cleanup for temporary allocations created with `new(origin=...)`. **Result** - Prevents the KeyError during accrual allocation onchange. - Allows users to create another allocation with the same accrual plan without triggering the RPC error. **opw-6390559** --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285799 Forward-Port-Of: odoo/odoo#283772
Pasting a copied URL over an existing selected link in the editor no longer causes an error. This helps users edit linked text more reliably without interruptions or lost work.
Original PR description
Steps to reproduce the issue: - Create a link in editor. - Copy another URL. - Select entire link. - Pasting copied link throws traceback. This issue happens after merging commit [1] where…
Steps to reproduce the issue:
- Create a link in editor.
- Copy another URL.
- Select entire link.
- Pasting copied link throws traceback.
This issue happens after merging commit [1] where `normalize_processors` callback returns nothing. After merging commit [2] each processor must return the original root if no processing is needed or processing is in place.
As a result, when this.processThrough("normalize_processors", container) is called from the `insert` method, the next processor in the chain uses `this.editable` as its default argument and removes the FEFF node, which is the anchor node. Later calling closestBlock(selection.anchorNode) returns null, resulting in the traceback. This PR aims to fix the traceback by returning the `root` in processor.
[1]: https://github.com/odoo/odoo/commit/be77a9a2003e09f4621d0ff774bf8749b326d037
[2]: https://github.com/odoo/odoo/commit/17d58d2fdf8da3a69c731fc5ea0d90b95e28efd6
task-6456004
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#283185This fix ensures mentions in social posts are correctly recognized and linked to the right profiles on Facebook, LinkedIn, and Twitter/X. It helps users publish clearer social content and avoids broken or incorrectly displayed mentions in the social posting tools.
Original PR description
This commit fixes an issue with the mention regexes for social_facebook as they weren't properly replaced by the initial mechanism. The initial mechanism was introduced by [1]. Now, we check every possible mention and if it is indeed a known mention, then we replace it by the correct link to their profile. [1]: https://github.com/odoo/enterprise/commit/4dacc5fce72687680080f75feef875fbfb3dbd15 task-6026857
This update corrects how the translation mode test module applies and removes its internal patches. It helps keep test behavior isolated so other environments or tenants are not affected after the module is uninstalled.
Original PR description
Fix patch for test_translation_mode Patch tools in a compatible way which will work for other tenants. Patch tools in a compatible way which will work after uninstallation. python code translation is not patchable by design. Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285538
Confirmed sales orders that are locked now consistently hide product configuration edit buttons, including configurable products, event tickets, and booths. This prevents users from seeing actions that should not be available and keeps the order lock behavior consistent across sales screens.
Original PR description
### Steps to Reproduce: 1. Go to Sales > Configuration > Settings 2. Under Quotations & Orders, enable "Lock Confirmed Sales" 3. Now create a Quotation with 2 products, 1 with attributes and 1…
### Steps to Reproduce: 1. Go to Sales > Configuration > Settings 2. Under Quotations & Orders, enable "Lock Confirmed Sales" 3. Now create a Quotation with 2 products, 1 with attributes and 1 without 4. Confirm the order 5. Hover over the product with attributes and notice that it allows you to to edit, but hovering over the other product does NOT reveal the edit icon ### Issue: When a user has configured their database to lock sale orders, it should not be possible to edit the products once the order has been confirmed. It currently only happens for products that have attributes. While standard products cannot be edited in a locked state, a missing condition on configurable products allows the button to persist when hovering over the description column. This creates an inconsistent UI state where users appear to have access to modify some of the line items. ### Solution: To fix this, we updated the `hasConfigurationButton` getter in `sale_product_mixin.js` to evaluate the parent document's locked state. By adding `!this.props.record.model.root.data.locked` to the getter's return logic, the edit button is now globally hidden across all related widgets (such as `sale_label_text` and `sale_product_field`) when the sales order is locked. This ensures that configurable products properly respect the locked document restrictions just as standard products do. Additionally, this locked condition was applied to the method overrides in the `event_sale` and `event_booth_sale` modules, ensuring that event tickets and booths also hide their configuration buttons on locked orders.Additionally, this locked condition was applied to the method overrides in the event_sale and event_booth_sale modules, ensuring that event tickets and booths also hide their configuration buttons on locked orders. opw-6512288 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284882
Opening the Field Service section from a helpdesk ticket preview no longer triggers an error after completed interventions are planned. This keeps customers and staff able to view intervention information reliably from the portal preview.
Original PR description
*=helpdesk_planning_field_service{,_sale_timesheet} Steps to reproduce: ------------------------- 1. Install helpdesk_planning_field_service_sale_timesheet with demo data. 2. Open a helpdesk team…
*=helpdesk_planning_field_service{,_sale_timesheet}
Steps to reproduce:
-------------------------
1. Install helpdesk_planning_field_service_sale_timesheet with demo data.
2. Open a helpdesk team (e.g., Customer Care) and enable field service planning.
3. Create a new ticket in Customer Care, plan two interventions, and mark them as completed.
4. Click the cog menu of the helpdesk ticket and click Preview.
5. In preview mode, click **Field Service** in the left sidebar.
Issue:
---------
A traceback occurs:
```python
File "/home/odoo/odoo/community/odoo/addons/base/models/ir_qweb.py", line 875, in _render_iterall
raise QWebError(qweb_error_info) from error
odoo.addons.base.models.ir_qweb.QWebError: Error while rendering the template:
KeyError: 'format_datetime'
Template: planning_field_service.portal_my_field_service_report_list
Reference: 866
Path: /t/t/t[3]/t/tbody/t/tr/td[1]/a/t
Element: <t t-out="format_datetime(intervention.start_datetime, dt_format='MMM d, YYYY')"/>
```
Cause:
---------
https://github.com/odoo/enterprise/blob/28637781cd3ffc4c3dc0c2016dd5d6051793f641/helpdesk_planning_field_service/controllers/portal.py#L59-L63
After this 6857d1a, date formatting was changed to use `format_datetime`, and [planning_field_service](https://github.com/odoo/enterprise/blob/28637781cd3ffc4c3dc0c2016dd5d6051793f641/planning_field_service/controllers/portal.py#L42) was updated accordingly. However, `helpdesk_planning_field_service` was not updated to pass `format_datetime` in the template values, causing a **KeyError** when opening the field service intervention list.
Solution:
-----------
Pass `format_datetime` in the template values, following the same approach used in `planning_field_service`.
opw-6467400
Forward-Port-Of: odoo/enterprise#129227
Forward-Port-Of: odoo/enterprise#128519The website shop search bar placeholder will now appear in the visitor's selected website language instead of always showing "Search" in English. This improves the multilingual shopping experience and avoids confusing non-English customers.
Original PR description
Problem: The search bar placeholder text is not being translated. Steps to reproduce: 1. Install e-Commerce 2. Go to Website > Configuration and add another language for the website 3. Go to Website > Shop 4. See how the search bar placeholder text is "Search" instead of being in the website's language Cause: The text was not extracted for translation because it is set inside `t-value=`. To be available for extraction, it should either be set inside `t-valuef.translate=` or should be the data content between the tags. opw-6486429 Forward-Port-Of: odoo/odoo#285011
The web client code was cleaned up by removing an outdated internal hook that is no longer used in the main codebase. This reduces maintenance overhead while keeping a temporary compatibility path for spreadsheet-related code that still depends on the older behavior.
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
This update simplifies how Odoo's messaging and live chat features handle certain internally calculated records. It should reduce unnecessary processing behind the scenes while preserving existing user-facing behavior in discussions, calls, and website chat.
Original PR description
Before this commit, twenty-four relations derive a record from a compute option: the model runs it, links the result and settles the pair at the end of the update cycle, while no inverse is declared, no one writes them and no one reads them as a stored value. This commit declares them with this.computed(), which holds the value in an owl computed of its own, without a relation and an update cycle around it. A compute that returned an object literal inserts its record itself, as a computed has no relation to do it for it, and correspondent keeps calling computeCorrespondent() so that the im_livechat override still takes effect.
This update reorganizes how Mail and Live Chat remember browser-stored preferences, such as chat or composer settings. It reduces duplicated background handling and helps ensure these saved preferences are tracked and cleaned up more consistently without changing the user experience.
Original PR description
Before this commit, a field kept in the browser local storage is declared with an option, fields.Attr(default, { localStorage: true }), and the model core carries everything that makes it work: a compute reading the entry, an onUpdate writing it back, a map of entries per record, a map from storage key to record and field per store, and a storage listener writing into the records.
This commit declares it on the record, as the other declarations that add a behaviour to a field:
before: compact = fields.Attr(false, { localStorage: true });
after: compact = this.localStorage(false);
The value follows its entry through two onChange observers of the record itself, so the model core keeps nothing about local storage. The record listens for the storage events of its own key and drops the listener with itself.
https://github.com/odoo/enterprise/pull/129818This change reorganizes how AI channel prompts are stored locally in Discuss conversations. It is an internal cleanup that should make the feature easier to maintain without changing the user experience.
Original PR description
Enterprise counterpart of "[REF] mail: declare a local storage field on the record", which explains the shape. The channel prompts are the only enterprise field kept in the local storage, and their onUpdate becomes an onChange next to the declaration. https://github.com/odoo/odoo/pull/285620
The mass mailing editor was updated to use newer underlying platform mechanisms as part of the Owl 3 migration. This helps keep the email marketing experience maintainable and compatible without introducing expected functional changes for users.
Original PR description
As part of the Owl 3 migration, replace onWillUpdateProps and useRecordObserver hook with the appropriate Owl 3 alternatives. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update renames an internal setting used by mail and live chat actions so its purpose is clearer to developers. It does not change customer-facing behavior, but it helps reduce confusion and future maintenance risk in messaging features.
Original PR description
This naming is confusing, action.dropdown signals that the action will open a dropdown menu while props.dropdown signals to render the action as a dropdown element.
This update removes an outdated internal developer helper from several Odoo Enterprise screens. It helps keep the interface code aligned with the newer framework, reducing future maintenance risk without changing day-to-day user workflows.
Original PR description
- https://github.com/odoo/odoo/pull/285708 See commit messages for details. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Manufacturing bill-of-material checks were streamlined so large purchase orders process faster when kit products may be involved. In the highlighted case, confirmation time with manufacturing installed drops from about 8.1 seconds to 6.9 seconds, improving responsiveness across related workflows.
Original PR description
Confirming a purchase order of 1000 lines - with only stock & purchase : time is 6.3secs - by adding mrp : time grows to 8.1secs Part of the difference comes from the time it takes to explode the (potential) kits. The refactor of _bom_find consists of: - signature change : company_id -> company_ids to allow searching within multiple companies in one go - return value change : the returned dict's key is now a tuple ( product, company_id or False) Calling _bom_find with no company given : retrieve result with ( product, False) Calling _bom_find with one or more company_id's : retrieve result with ( product, company) -> for _bom_find on record sets having the fields product_id & company_id With this, use case time falls to 6.9secs This will obviously have performance impact on many use cases.