Monday, August 31, 2026
110 changes · master
Security fixes and vulnerability patches
Custom signing fields can now be limited to selected user groups instead of being only private or visible to all employees. Sensitive HR-related signing fields are restricted to relevant HR and payroll roles, and only template owners or Sign Administrators can change template access settings.
Original PR description
Before this PR Custom sign field types (`sign.item.type`) were either private to their creator or, if marked `shared`, visible to every internal user. There was no way to make a custom field…
Before this PR Custom sign field types (`sign.item.type`) were either private to their creator or, if marked `shared`, visible to every internal user. There was no way to make a custom field available to specific groups only. After this PR Added a new "Used by" (`authorized_group_ids`) field. Marking a field `shared` still makes it visible to everyone, same as before. Left unshared, you can instead pick one or more groups in "Used by" to make the field visible to just those groups instead of making it fully private or fully public. HR-linked fields (Legal Name, Private City, Country Name, Private Street) are now restricted to Recruitment Interviewer (`group_hr_recruitment_interviewer`) + Payroll Assistant (`group_hr_payroll_user`) via "Used by", instead of being shared. Additionally, in `sign.template` only the template owner or Sign Administrator can edit authorized_ids/group_ids. the "Access Rights" menu item and Authorized Groups field are hidden in the UI otherwise. Task-id: 6425404
Enhancements to existing features
Portal users should see much faster results when filtering their tasks by milestone. This improves responsiveness on the My Tasks page by avoiding a slow database search path.
Original PR description
Go to `/my/tasks`. The search on milestones is really slow. Performance improvement for a portal user: | | Time | Query plan | |--------|--------|--------| | Before | ~3.6s |…
Go to `/my/tasks`. The search on milestones is really slow. Performance improvement for a portal user: | | Time | Query plan | |--------|--------|--------| | Before | ~3.6s | https://explain.dalibo.com/plan/dga21917bc86eg54 | | After | ~60ms | https://explain.dalibo.com/plan/91b818beg2f1077f | For portal users, complex record rules require joining the `project` table. Because the query includes a `limit=1`, the postgresql query planner assumes it will find a matching row almost immediately. Hoping for a "fast exit", it chooses to sequentially scan the `project_id` index to perform a Merge Join. However, if it doesn't find a match early on, it ends up scanning the entire index, resulting in a massive slowdown. We update the `search_count` constraint from `limit=1` to `limit=80`. By increasing the limit, we alter postgresql's cost estimation. The planner can no longer assume a cheap "fast exit" is guaranteed, which forces it to abandon the flawed Merge Join strategy. Instead, it correctly evaluates the query and chooses the index on `milestone_id` to retrieve the records. task-6373729 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283239
Resolved issues and error corrections
Customers previewing helpdesk tickets can now see the Field service button when related interventions exist. This fixes a visibility issue caused by a portal display change, helping users access completed field service information as expected.
Original PR description
Steps to reproduce: -------------------------- 1. Install helpdesk_planning_field_service_sale_timesheet and website with demo data. 2. Open a helpdesk team (e.g., Customer Care) and enable field…
Features or functions removed from Odoo
The French PDP e-invoicing pilot phase option has been removed now that the pilot deadline has passed. This simplifies setup and registration screens by aligning them with the current compliance timeline.
Original PR description
The pilot phase was there if people wanted to send before the deadline. The deadline has been reached, so we can remove the field from the view. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285268 Forward-Port-Of: odoo/odoo#284186
Code cleanup and technical improvements
Event track location display has been moved into the main website event track feature instead of remaining as a separate add-on. This simplifies setup and maintenance while keeping the location display available where event track management is used.
Original PR description
This feature was added as a dedicated module because it was added in stable version 19.3 . We can now merge it directly into track module where it belongs. Task-6515688
Warehouse users can now split stock move lines into equal-sized packages directly from detailed operations instead of manually creating each line. The process keeps the correct source locations and can suggest package size from the selected package type, making packing faster and less error-prone.
Original PR description
Before, whenever a user wanted to split move lines in different equal by size packages, user had to manually add new lines. Now by provividing the size of a package, it can be done automatically. This functionality takes into account current locations, and preserves them for newly created move lines. Moveover, if several move lines are picked, it is impossible to split them together, only separately. Moveover, Package size can be calculated automatically by providing Package Type. We check the UoMs that have this package type, and get the relative factor with the move UoM. If several UoMs have this package type, then the first one is picked. task-6034274 I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update modernizes internal database query handling in sales, online shop, loyalty, and payment test areas using Odoo's safer query-building framework. It is intended to preserve existing behavior while reducing future maintenance and injection-risk concerns.
Original PR description
The framework provides a wrapper to compose SQL queries safely: as long as the format string is written in the source, the resulting object is safe from injection, and the parameters of nested fragments are merged automatically. Convert the remaining queries in our scope to use it, where applicable. The generated queries and their parameters are unchanged. task-6297256 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Manufacturing users can now open a complete, ordered view of a bill of materials, including nested subassemblies, directly from the BoM form. This makes it faster to review and update components without manually opening each related BoM one by one.
Original PR description
Currently, when a BoM contains components with child BoM, clicking `Compare BoMs` shows the immediate components only in list view. Users still need to open each BoM separately to edit nested…
Currently, when a BoM contains components with child BoM, clicking `Compare BoMs` shows the immediate components only in list view. Users still need to open each BoM separately to edit nested components. This change will adds a new smartbutton that shows: - Components: number of components of the BoM - SubAssembly: number of sub BoMs inside the BoM Clicking the smartbutton opens the list of exploded components by following the hierarchy order, which provides a complete view of the BoM structure in a single place, allows user to update nested components and without navigating manually. ### About `forced_order_ids` context: ### - The action uses a `forced_order_ids` context key to preserve the exploded hierarchy order instead of the model's default ordering when the list view performs a `search_fetch()`. - When opening the exploded list view -> product form -> BoM of that product, `forced_order_ids` should be reset to `False`. Otherwise, if the same child BoM is added multiple times, the BoM show repeated BoM lines. [video](https://drive.google.com/file/d/1M5k4XXGvr8KASzhBsRRByV3vepM8BBn1/view?usp=drivesdk) - When the user searches for a component through the search panel, `forced_order_ids` should filtered using the records returned by the `super()` call, which only contains the matched records. Without that filtering, the search would stop working correctly and would return all `forced_order_ids`. [video](https://drive.google.com/file/d/1De0IfTyPPTjk02rCOh2yJPHa9wI0Zi_W/view?usp=drivesdk) - It is also used to change the order of the fields in the search view, because when the list is opened from the `Components/SubAssembly` smartbutton, the component search should be on top, in other cases the BoM search should be on top. Ent PR https://github.com/odoo/enterprise/pull/120254 task-6247051
Warehouse barcode scanning now automatically creates a package when a scanned packaging barcode has a package type, such as a box for a pack of six. This helps keep grouped items packed correctly during stock and manufacturing barcode flows, reducing manual packing steps and improving consistency.
Original PR description
When users scan packaging barcodes, they want them to be stored together for UoMs with packaging type specified. For example, if Pack of 6 is scanned and it has a packaging type, you would like a package to be automatically created if packaging barcode for Pack of 6 was scanned. This commit implements exactly that. task-6034274
Messaging-related assistant rules are now treated as side activities by default, so quick message interruptions do not replace the user's current project or task in Timesheets. Users can still change this setting when needed, preserving flexibility while reducing accidental context switches.
Original PR description
- Messaging is usually a short interruption, so those assistant rules should not replace the current project/task. Compute `side_activity` so new messaging rules get it checked and the user can still override it. task-6486402
The manufacturing bill of materials screen now places the Schedules button next to the BoM Overview button. This makes related planning and overview actions easier to find, improving navigation without changing underlying functionality.
Original PR description
Move the `Schedules` smart button next to `BoM Overview` to keep related smart buttons together. Com PR https://github.com/odoo/odoo/pull/267605 task-6247051
The My Planning calendar no longer shows the Resources filter when Field Service is installed. This prevents users from seeing a filter that was intended to be disabled, making the planning view cleaner and less confusing.
Original PR description
This PR removes the `resource_ids` filter from the "My Planning" calendar view when Field Service is installed. It was already supposed to be disabled but `filters=0` was not working properly. task-6486260
Timesheets billing target menus and settings have been reorganized and renamed to make them easier to understand. The update also keeps related menu visibility in sync when leaderboard settings change, reducing confusion from outdated menu options.
Original PR description
In this commit, we clean the billing target and menus of Timesheets. In short, we: - Add a new "Billable Time" parent menu that is hidden when billable time targets are not displayed. - Hide the "Tips" configuration menu when the "Billing rate leaderboard" is disabled. - Reword the billable time settings (billable time targets & billable time leaderboard). - Rename the billable time target labels in their configuration view and on the Employee form. Additionally, we ensure the menu cache is invalidated when the leaderboard setting changes, the same way as currently done for the billing rate setting. Without this, the "Tips" configuration menu would stay stale until the cache got cleared by some potentially unrelated reason. task-6486399
Jordan e-invoicing now shows all submission issues together before invoices are sent, helping users fix problems faster and avoid repeated error rounds. Rejected invoices are easier to investigate with clear rejection details and XML download access, while demo invoices and receipts are visibly marked as non-fiscal documents.
Original PR description
Description of the issue/feature this PR addresses: Rework the UX of the Jordan e-invoicing (JoFotara) flow: where submission errors are reported, how a rejected invoice exposes its XML, where the…
Description of the issue/feature this PR addresses: Rework the UX of the Jordan e-invoicing (JoFotara) flow: where submission errors are reported, how a rejected invoice exposes its XML, where the JoFotara fields live on the invoice, and how demo documents identify themselves. Current behavior before PR: Configuration errors mask invoice-level ones, so the user fixes the settings and gets a second round of errors. They arrive as a pop-up after the Send & Print wizard is confirmed, one alert per invoice. The invoice form shows a yellow banner and a "Download XML" link restricted to base.group_no_one, so a rejected invoice offers no practical way to inspect what was sent. Demo mode is invisible: the checkbox reads "JoFotara (Jordan EDI)" either way, and demo PDFs and POS receipts look like valid fiscal documents. Desired behavior after PR is merged: All errors are reported together as danger alerts inside the wizard, before submission — one alert per defect, with a "View Invoices" action listing every invoice sharing it. A rejection opens a dialog with JoFotara's message and buttons to copy it or download the submitted XML, for any user. The JoFotara fields, plus Payment Method and "Reversal of", move into a "JoFotara" group on the Other Info tab. task-6321488 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Manufacturing scheduling now skips over fully occupied time blocks instead of checking many tiny windows one by one. This significantly speeds up planning when work centers are heavily booked, especially for very short work orders.
Original PR description
### Description of the issue/feature this PR addresses: The workcenter planning logic in _get_first_available_slot can become inefficient when searching for very short available slots. The method…
### Description of the issue/feature this PR addresses: The workcenter planning logic in _get_first_available_slot can become inefficient when searching for very short available slots. The method repeatedly builds small candidate time windows and checks them against existing workorder and leave intervals, potentially iterating many times before finding a free slot. This leads to unnecessary computational overhead in scenarios where a large number of busy intervals exist and the remaining duration to schedule is small. ### Current behavior before PR: The planner checks for conflicts by computing the intersection between the candidate window and the busy intervals. When a conflict is detected, the candidate window is shifted forward (or backward) to the end (or start) of the intersection, and the process is repeated until a free slot is found. This approach requires repeatedly performing full interval merge operations, which becomes disproportionately expensive when the candidate windows are very small and the loop iterates many times. ### Desired behavior after PR is merged: The planner uses a new Intervals.conflicting() helper to retrieve the entire busy interval that overlaps with the candidate window. Instead of advancing only to the end of the intersection slice, the planner can jump directly to the end (or start) of the full busy interval. This avoids repeated full-merge work, reduces the number of iterations needed to find a valid slot, and prevents pathological performance slowdowns in short-duration planning scenarios. ### Benchmarks Profiling _get_first_available_slot with different workorder durations. Database has multiple months that are fully booked. Speedup is more dramatic with shorter durations but there is at minimum minor improvements across the board. | Work Order Duration | Before | After | | --- |---|---| | 1sec | ~2.5min | <1sec | | 1min | ~2sec | <1sec | ### References opw-5437256 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284278 Forward-Port-Of: odoo/odoo#246015
The map view now more reliably opens location details when users select an item and keeps their map layout when they leave and return. Users also get a cleaner side panel with resizable width, making field service planning easier and less repetitive.
Original PR description
First commit fixes an issue where clicking a list item to center the map and open its marker's popup often did nothing at all. The pending record was stored in a plain, non-reactive field, only ever…
First commit fixes an issue where clicking a list item to center the map and open its marker's popup often did nothing at all. The pending record was stored in a plain, non-reactive field, only ever rechecked by updateMap()'s useLayoutEffect, which reruns on every patch of the component - but nothing about the click itself reliably causes a patch: closing pinListPopover (a mobile-only bottom sheet) only triggers one if it was actually open. On desktop, where it never is, closing it is a no-op, so no patch happens and the pending record is never rechecked. The popup would then only show up later, incidentally, whenever some unrelated interaction (toggling a group fold, expanding Unlocated, ...) happened to trigger a patch of its own. Even when it did open, doing so before the map had finished panning to it made it visibly reposition/flicker, since it isn't tracked by Leaflet's own pan animation the way a native Leaflet popup would be. Replace the deprecated Owl 2 useLayoutEffect compat shim with native onMounted/onPatched, and branch on whether pinListPopover is actually open: when it isn't (desktop), open the popup right away instead of depending on a patch that was never going to happen; when it is (mobile), wait for the patch that closing it triggers - the same one that recreates the markers - before opening the popup, so it anchors to the freshly created marker element instead of the stale one about to be removed. Also wait for the pan's moveend before creating the popup, to avoid the repositioning/flicker. Second commit preserves map view state when navigating away to another view and returning, preventing the map from resetting to its default initial state. The following state variables have been moved into the map model so they can be exported via `getLocalState` and restored upon remounting: * **Group Folding:** Retains folded group states via `closedGroupIds`. * **Unlocated Panel:** Maintains the expansion toggle state of `expandUnlocated`. Since closed groups now outlive a reload, the groups a view folds by default can no longer be re-applied on every load: they come from `_getDefaultClosedGroupIds`, only consulted when the closed groups are (re)initialized, i.e. when the groupBy changes. Field service maps fold their material resources through that hook, instead of overwriting `closedGroupIds` after each load, which discarded both the restored state and whatever the user had folded. The current user's position is instead persisted in `localStorage`, keyed by the view and action. When it comes from an address search or from the company's address, the actual coordinates are cached. When it comes from the browser's geolocation API, only the fact that it should be looked up again is cached, since GPS coordinates can quickly become stale. Third commit refines list sidebar and group header styling. Group headers now span the full width of the list sidebar and darken on hover, like group rows in list views. The group pin icon is narrower so it no longer feels bloated next to the group name, and the Google Maps button in group headers no longer has a background or hover effect of its own. Also unifies the "clickable" styling of located pins and unlocated records under a single class, and aligns the unlocated section's fold icon with the one used for other groups. Record rows now carry their own horizontal padding instead of the list itself, so their hover background spans the sidebar's full width. The "my location" button icon uses the default icon size, and the pin list no longer keeps a stray bottom spacing. Fourth commit adds the possibility to resize map view's side panel (pin list) similarly to what is done in the search panel or gantt view. task-6431782
Users can now switch to a Kanban layout when selecting documents from the chatter, making it easier to browse files visually. The dialog has also been simplified by removing less relevant fields and filters such as Favorites, Activities, and Owner.
Original PR description
`*` = ai_documents_source, documents_spreadsheet **Purpose:** When we add document in a chatter, the file selection dialog currently displays only the list view. **Specifications:** - Add a Kanban view option to the document selection dialog. - Remove the Favorites field/filter. - Remove the Activities field. - Remove the Owner field. Task-6236894
AI agents can now work through longer tasks before reaching their activity limit. If they do reach the limit, they are guided to summarize progress and ask the user whether to continue instead of abruptly ending the conversation with an error.
Original PR description
Before this change, AI Agents were limited to a default of 20 successive API calls (agentic loop turns) before stopping. When this limit was exceeded, the Python backend raised a hard UserError exception. This commit increases the default fallback limit as well as introducing a graceful fallback for the case when that limit were to be reached. task-6313259
Document and folder action menus are now more consistent across views, making common actions easier to find. Users can copy links from the sidebar and add stars from right-click or top action menus, while the folder cog menu has been simplified by removing the Info & Tag action.
Original PR description
Purpose ======= Remove the "Info & Tag" action from the folder cog wheel. Make the order of the action consistent across the views, add "Copy Link" in the side bar, and "Add star" in the right-click / top actions. Task-6474895
The error shown when a planned date is removed while scheduling a shift has been reworded to be easier to understand. This helps users identify what went wrong and correct the scheduling issue more quickly.
Original PR description
In this commit, we reword the error message that is raised when planning a shift from the shifts to schedule and removing the planned date to be clearer. task-6394257
Employee types must now include a country, helping ensure payroll-related employee categories are consistently tied to the correct localization. This supports Belgian payroll data cleanup and prevents new employee types from being created without required country information.
Original PR description
In enterprise: - All missing employee types country_id value from Be localization are set to Belgium. See: odoo/enterprise#129867 And any newly created employee types must set a value to the country_id field. Hence, this commit that add the argument required=True to the field country_id. task: 6511484
Belgian payroll calendars now show working time reorganisation details for variable schedules. Users can record a Time Reorganisation Amount for credit-time arrangements, with automatic full-time value filling in one case and a blank value available in another.
Original PR description
. Show Working Time Reorganisation field with the variable calendars . Add Time Reorganisation Amount field to show mount of time for the Credit-Time . If user select 3, display a new field Time Reorganisation Amount (float) below and made it filled with the same value as Hours per week (we expect a full credit time) . If user select 4, display the same field Time Reorganisation Amount (float) below and let it empty task-6449163
The point of sale now highlights available loyalty rewards with an attention animation, helping cashiers notice and apply customer benefits more easily. Text input popups can also clean pasted content by removing line breaks, reducing formatting issues during checkout workflows.
Original PR description
In This Commit: ================ - Add removeNewLines option to TextInputPopup to strip newlines on paste - Add a reward attention animation to rewards button when active Task-6462056
The point of sale screen now shows the percent symbol after the down payment value instead of before it. This aligns the display with common visual conventions and makes quote down payments easier to read for users.
Original PR description
Previously, the % symbol was located to the left of the price when making a down payment in the PoS for a quote. This commit moves it to the right to conform to visual conventions. Task-6392074
Long-term sickness absences can now be separated into the appropriate sick leave categories based on duration. This helps payroll and HR reporting reflect guaranteed salary, unpaid sick leave, and long-term sick periods more accurately for extended absences.
Original PR description
This commit will support the new split for Long Term Sickness (LEAVE280) Ex:- Leave from 1st Jan 2026 to 30th Jan 2027. This time off will be split into: - LEAVE110 - Sick Time Off: 30 days - LEAVE214 - Sick Time Off (Without Guaranteed Salary): 335 days - LEAVE280 - Long Term Sick: 30 days task-[6307896](https://www.odoo.com/odoo/project/1251/tasks/6307896) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Belgian payroll now separates employee sick leave after 12 months into a dedicated long-term sickness category. This improves payroll accuracy and compliance by distinguishing long-term sickness from earlier unpaid sickness periods, including relapse cases.
Original PR description
Currently, a sick leave for an employee is split into LEAVE110 (guaranteed salary, first 30 days) and LEAVE214 (no guaranteed salary, after 30 days). This commit adds new split for Long term sickness…
Currently, a sick leave for an employee is split into LEAVE110 (guaranteed salary, first 30 days) and LEAVE214 (no guaranteed salary, after 30 days). This commit adds new split for Long term sickness (LEAVE280) for employee which is applied after 12 months sickness. What changed: - New helper `_get_l10n_be_long_term_sick_cutoff_date` return the cuttoff date at which a sickness chain crosses the 12-month threshold accounting relapse using `_l10n_be_get_sick_leave_twelve_months_cutoff_date` which is moved from `hr_payslip` to `hr_employee` as it will be commonly used for leave split and the paylsip work entry generation. - New helper `_get_l10n_be_long_term_sick_split` takes the existing LEAVE110/LEAVE214 split and converts whatever part of it falls on/after the 12-month cutoff into LEAVE280. If the cutoff falls in the middle of a segment, that segment is cut in two. - Applied this check to every place in `_get_l10n_be_sick_leave_split` that can return a final result. - `_get_leave_work_entry_type_dates` (legacy support for old, unmigrated data) gets the same 12-month check before its existing 30-day check. task-[6307896](https://www.odoo.com/odoo/project/1251/tasks/6307896)
This update adds support for China's differential taxation rules in invoicing, allowing businesses to manage balance deductions and issue the appropriate net or full amount Fapiao. It improves VAT accuracy by validating deduction details, creating offset entries automatically, and keeping links for audit traceability.
Original PR description
Support Balance Deduction for China's Differential Taxation rules, where businesses may issue Net Amount Fapiao or Full Amount Fapiao depending on the applicable taxation method. The selected method…
Support Balance Deduction for China's Differential Taxation rules, where businesses may issue Net Amount Fapiao or Full Amount Fapiao depending on the applicable taxation method. The selected method determines how the deduction is applied and how the corresponding Output VAT Offset Entries are generated, ensuring accurate VAT accounting and traceability. - Add invoice-line-level Balance Deduction management through dedicated wizard. - Validate applicable invoice lines before posting, ensuring required deduction information is provided and taxes meet the supported percentage-tax requirements. - Generate Output VAT Offset Entries according to the selected Differential Taxation Method: - Link generated offset entries to the originating invoice and invoice lines for accounting traceability. - Reverse previously generated offset entries when the invoice is reset to draft or Balance Deduction information is reset, preserving accounting consistency and auditability. task-[6104958](https://www.odoo.com/odoo/project/967/tasks/6104958)
Currency amounts written in words now use language-aware forms where supported, so documents can show grammatically correct currency names and number wording. This improves localization for languages with complex plural and gender rules while keeping existing formatting behavior when no specialized wording is available.
Original PR description
## Summary POC exploring a better use of `num2words` in `res.currency.amount_to_text()` (core `base` module). Today `amount_to_text()` converts the integral/fractional parts with a plain…
## Summary POC exploring a better use of `num2words` in `res.currency.amount_to_text()` (core `base` module). Today `amount_to_text()` converts the integral/fractional parts with a plain `num2words(...).title()` cardinal conversion, and always uses the currency's single-form `currency_unit_label`/`currency_subunit_label`. This is fine for English-like languages, but wrong for languages with grammatical number agreement: many Slavic languages use one of 3 noun forms depending on the last digit(s) of the amount (e.g. Ukrainian "гривня"/"гривні"/"гривень"), and some also need the numeral itself gendered (e.g. "одна гривня", not "один гривня", for 1 UAH). `num2words` already ships this data per `(language, ISO currency code)` via `CURRENCY_FORMS` + `pluralize()` + `_money_verbose`/`_cents_verbose`, normally consumed through its own `to='currency'` mode. That mode is not used directly here because it changes Odoo's current sentence shape (it always renders the subunit clause, even when zero, and joins the two clauses with its own separator instead of a translatable "and"). This PR uses that per-language data to build just the two correctly-inflected words, and plugs them into Odoo's *existing* template: - the zero-subunit clause is still dropped (no "...and zero cents"), - the two clauses are still joined with the translatable `"and"`. When `num2words` has no currency data for the `(language, currency)` pair, behavior falls back unchanged to the previous plain-cardinal + translated-label path. ## Example (Ukrainian / UAH) | Amount | Before | After | |---|---|---| | 1.00 | `Один Hryvnia` | `одна гривня` | | 2.00 | `Два Hryvnia` | `дві гривні` | | 5.00 | `П'Ять Hryvnia` | `п'ять гривень` | | 21.56 | `Двадцять Один Hryvnia and П'Ятьдесят Шість Kopiyka` | `двадцять одна гривня and п'ятдесят шість копійок` | (English/EUR and other currencies `num2words` has no data for are unaffected.) ## Scope / open questions (see inline code comments) - This is a POC: only currencies `num2words` explicitly models (`CURRENCY_FORMS`) get the improved output; everything else keeps today's behavior byte-for-byte. - The untranslated literal `"and"` in some locales is a pre-existing translation-coverage gap, unrelated to this change. - `num2words`' own data isn't uniformly correct/complete across all its language modules (e.g. English `EUR` forms don't pluralize `"euro"` upstream) - that's an upstream data quality question, not something this PR should paper over. - Longer term this raises the question of whether `currency_unit_label`/`currency_subunit_label` should stay only as the fallback path.
Users can now update tags directly in the subscriptions list instead of opening each subscription individually. This makes it faster to organize one or many subscriptions at once, improving day-to-day subscription management.
Original PR description
Before this commit, the Tags column in the subscriptions list view was read-only, preventing tags from being edited directly from the list. After this commit, tags can be edited directly from the subscriptions list, either on a single subscription or on multiple selected subscriptions at once. task-6222724
Belgian payroll now includes a warning when an employee may not meet the required minimum age rules. This helps payroll teams spot potential compliance issues earlier and reduce manual checks.
Original PR description
task-6515312
Point of Sale sessions with many invoiced bank payments now close much faster by processing payment reconciliation and invoice receivable line creation in batches. This reduces the risk of session closing timing out for businesses with high transaction volumes, improving reliability at end of day.
Original PR description
Steps to reproduce ------------------ 1. On a bank payment method, enable "Identify Customer". 2. Create a lot of orders paid with this method and invoice them (the customer reporting the issue had…
Steps to reproduce ------------------ 1. On a bank payment method, enable "Identify Customer". 2. Create a lot of orders paid with this method and invoice them (the customer reporting the issue had 2081 orders). 3. Close the session. The close takes several minutes, and on a remote database the request is killed by the worker time limit before it completes. Cause ----- `_reconcile_account_move_lines` reconciles each group of lines with its own `reconcile()` call, one per payment. Every call creates its partials and triggers the recompute cascade of the ORM, which searches `account.move.line` over the whole set of payments of the session, so the cost of a single call grows with the number of payments. `_create_invoice_receivable_lines` has the same shape: the values are grouped per payment, so every group holds a single value and the lines are created one `create()` call at a time. opw-6242303 already batched the creation and the posting of the split bank payments, and the reconciliation of their receivable lines, but only for the orders that are not invoiced. Invoiced orders go through `split_inv_payment_receivable_lines`, which was left untouched. Fix --- Gather every reconciliation of the session into a single `_reconcile_plan` call. The entries of the plan are processed independently and in order, so the result is the same as reconciling them one by one, but the recompute cascade runs once instead of once per payment. Create all the invoice receivable lines in a single `create()` call and dispatch the records back to their payment method or payment afterwards. Benchmark --------- Closing a session of 2081 invoiced orders on a copy of the customer database: - before: 558s - after: 54s opw-6458271 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285183 Forward-Port-Of: odoo/odoo#281495
This update improves the HTML editor so users can keep editing list items even when special non-editable elements are present. It also restores safeguards that prevent editing placeholders from appearing in inappropriate places, reducing frustrating cursor behavior and regressions around links.
Original PR description
If a list item has a selection blocker, the user can be stuck and forced to move to the previous or next block instead of being able to continue to edit the list item. To get around this, this commit allows selection placeholders in list items. task-6394918 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279432 Forward-Port-Of: odoo/odoo#278323
Pay later receivables in Point of Sale settlement are now reconciled in one grouped operation instead of repeated partner-by-partner processing. This keeps the accounting outcome unchanged while reducing processing overhead, especially for sessions with many customers.
Original PR description
The pay later receivable lines are reconciled with one `reconcile()` call per partner, and each call filters the whole set of lines again. Reconcile them in a single `_reconcile_plan` call grouped by partner instead: the result is the same, but the recompute cascade of the ORM runs once instead of once per partner. opw-6458271 Related: https://github.com/odoo/odoo/pull/281495 Forward-Port-Of: odoo/enterprise#129637 Forward-Port-Of: odoo/enterprise#127415
Belgian payroll calculations for copyright royalties are updated to reflect 2026 rules. IP royalties paid through payroll will now include social security contributions and use a flat 15% withholding tax, improving compliance with Belgian legislation.
Original PR description
As of 2026, copyright (IP) royalties paid through the payroll are subject to ONSS and their withholding tax becomes a flat rate: - new rule "Intellectual Property - ONSS Part" (IP.PART.ONSS) computes the 13.07% ONSS on the IP part of the remuneration - the IP withholding tax is now a flat 15% (new rule parameter ip_tax_rate) applied on the IP part net of its ONSS part, replacing the 50%/25% cost-deduction brackets and the withholding cap (ip_deduction_bracket_1/2 are no longer referenced by the code) Forward-Port-Of: odoo/enterprise#129136
Inventory batch picking is now part of the main stock app instead of being split across separate add-on modules. This simplifies setup and maintenance for businesses using delivery, localization, and batch picking features, while also removing unused legacy code.
Original PR description
(Re)opening an useless PR for the sake of the runbot's builds... **Enterprise PR**: odoo/enterprise#128175
This update addresses common website quality issues flagged by Lighthouse, especially around accessibility for keyboard and screen reader users. It also improves privacy and performance by hosting Google fonts locally by default, helping websites provide a smoother and more compliant visitor experience.
Original PR description
This PR fixes some common Lighthouse issues. Please have a look at the different commits for more information.
Steps to reproduce: -------------------------- 1. Install helpdesk_planning_field_service_sale_timesheet and website 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. Issue: ------- The "Field service" button is not visible. Cause: ------- Earlier, portal card visibility and existence were controlled directly in the QWeb template. After the portal refactoring, their visibility and existence are now managed by `portal.entry` records. As a result, the field service entry is incorrectly considered unavailable, causing the test to fail on runbot. Related build: https://runbot.odoo.com/runbot/build/123497806 Fix: ------ Determine the visibility of the "Field service" portal entry using the corresponding `portal.entry` record. (Similar https://github.com/odoo-dev/odoo/commit/84ccbded9f4f1f00359b2eef59bce9527368fb05) Related pr: https://github.com/odoo/enterprise/pull/129227 opw-6481737 Forward-Port-Of: odoo/enterprise#129860
The Sales dashboard buttons now display correctly when selected, with no clipped top border. Cart-related buttons also have a consistent width, making the dashboard look more polished and easier to scan.
Original PR description
Fix the top border of the dashboard buttons being cut off when selected. Also set a consistent width for all cart buttons using CSS. Enterprise PR: https://github.com/odoo/enterprise/pull/129874 **Before:** <img width="655" height="171" alt="before_sale1" src="https://github.com/user-attachments/assets/e86716b7-3eba-4e7a-a5ed-510a3bc0ef46" /> **After:** <img width="591" height="189" alt="after_sale" src="https://github.com/user-attachments/assets/fff6565e-bd1f-4f94-9089-5a951b60f5bd" />
This fix removes an unnecessary testing dependency from the base import module. It helps keep automated checks more reliable and easier to maintain without changing everyday user workflows.
Original PR description
Removes the hard dependency on `test_tools` and forces the tests of `test_cloc` to run on `base_import_module` (`allow_inherited_tests_method`). --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Self-order preparation receipts now include the customer name when it was entered for the order. This helps staff identify and prepare orders more accurately, reducing confusion during service.
Original PR description
The customer name is written in `floating_order_name` which is never passed to the preparation receipt in self order. This commit fixes it. Forward-Port-Of: odoo/odoo#285219 Forward-Port-Of: odoo/odoo#284454
This fix prevents broad internal searches when security rules rely on document-related fields, avoiding cases where systems with many attachments could become unable to fetch product documents efficiently. It improves reliability and performance for databases with large numbers of attachments without changing user-facing workflows.
Original PR description
When the security domain uses a many2one field that needs the `search_domain` context, the field itself might not be present in the user-given domain. When this happens, we assumed to search on all records which is too much in the case of attachments. The practical example is product.document where a simple fetch could not be done anymore on databases having a lot of attachments. opw-6486492 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285146
The rental dashboard buttons now display correctly when selected, with their top borders no longer visually cut off. This provides a cleaner and more consistent dashboard appearance for users managing rentals.
Original PR description
Fix the top border of the dashboard buttons being cut off when selected. The community PR adding CSS to ensure all buttons have the same size also implicitly applies to this dashboard. Community PR: https://github.com/odoo/odoo/pull/285700 **Before:** <img width="541" height="178" alt="before_rental" src="https://github.com/user-attachments/assets/61c72e16-0de6-4324-9460-c4dc547c1ed0" /> **After:** <img width="574" height="182" alt="after_rental" src="https://github.com/user-attachments/assets/20b0bd60-7d07-4b9a-bac7-18f8b6672e54" />
Users can again create folders, links, and document requests in the Documents app without seeing an error. The fix restores the proper behavior after a recent internal code change, preventing interruptions in document organization workflows.
Original PR description
The recent JS refactoring in commit b0aeefd7a1e moved several logic hooks into class methods, but they lost their execution context when passed down as props to child components. Steps to reproduce: 1. Open the Documents app. 2. Try to create a new folder, URL, or document request from the UI. 3. Traceback appears: `TypeError: Cannot read properties of undefined`. This commit fixes the issue by binding the component's context to these callback methods during setup so they execute correctly. Task-6524435
Belgian payroll reporting now uses the correct DMFA remuneration code for benefits in kind when an employee has no working days on the payslip. This helps ensure payroll declarations comply with Belgian reporting rules and reduces the risk of incorrect submissions.
Original PR description
Previously, BIK remunerations were reported in the DMFA using code 1. This change uses remuneration code 2 for BIK in months where the employee has no working days on the payslip. task: 6431491
Belgian SODA file imports now work for users who do not have Analytic Accounting access when that feature is not enabled. This prevents an unnecessary access error and lets affected accounting users complete their import workflow normally.
Original PR description
**Description of the issue/feature this PR addresses:** When importing a SODA XML file, users without the Analytic Accounting group encounter an access rights error even if Analytic Accounting is not…
**Description of the issue/feature this PR addresses:** When importing a SODA XML file, users without the Analytic Accounting group encounter an access rights error even if Analytic Accounting is not enabled. This occurs because the import wizard reads the `analytic_account_id` field on the `soda.analytic.mapping` model to build an internal dictionary of departments. Because this field is restricted to the Analytic Accounting group, the evaluation of this field crashes the import for users even when the Analytic Accounting feature is disabled. This commit resolves the issue by using `.sudo()` on the analytic mapping recordset to bypass the field-level group restriction. **Steps to reproduce:** - Log in as Mitchell Admin, change company to “My Belgian Company” - Settings > Users & Companies > Users > Mitchell Admin > Access Rights > Extra Rights > ensure “Analytic Accounting” is unchecked - Also ensure Mitchell Admin is not part of the “Analytic Accounting” group - Accounting Dashboard > remove “Favorites” from filter > drag & drop a SODA XML file to “Miscellaneous Operations” > save > observe Access Error **Current behavior before PR:** - Users who don't belong to the Analytic Accounting group encounter an access error when attempting to import SODA XML files, even when the Analytic Accounting feature isn't enabled **Desired behavior after PR is merged:** - Those users no longer receive an access error opw-6376039 Forward-Port-Of: odoo/enterprise#127867
The Peruvian sales ledger now reports the full gross value of sales affected by the 3% IGV withholding. This aligns the report with SUNAT expectations and avoids understating sales totals because the withholding is handled as a payment-time mechanism.
Original PR description
The 3% IGV withholding is a negative sale tax, so it reduced amount_total and the 14.4 ledger reported a net total. SUNAT expects the gross total of the operation, the withholding being a payment-time mechanism. task-5935227 Forward-Port-Of: odoo/enterprise#129089 Forward-Port-Of: odoo/enterprise#128849
Belgian payroll now correctly applies an employee's default private fuel card use when calculating payslips, when applicable. The related fuel card private use amount is also categorized as a benefit in kind, helping ensure the right social security and withholding treatment.
Original PR description
FUEL_CARD_PRIV never fired: nothing copied the employee's fuel_card_personal_use default into the payslip's property input. Fixed by seeding it in _compute_input_line_ids(), gated on fuel_card set, no company car, no mobility budget. FUEL_CARD_PRIV is also a Benefit in Kind (ONSS + withholding), like ATN.INT, but was missing the BIK category. Added it. Task 6469003 Forward-Port-Of: odoo/enterprise#129581 Forward-Port-Of: odoo/enterprise#128789
This update fixes the placement of add and remove suggestion buttons in the timesheet assistant so they stay within the visible border. It improves the visual polish and usability of the assistant without changing its functionality.
Original PR description
This commit ensures that the buttons to add/remove suggestions fit the border. task-6492978 Forward-Port-Of: odoo/enterprise#129345
LinkedIn posts now show hashtags correctly in the feed view. This helps users review and manage social content as it will appear, reducing confusion when monitoring published or scheduled posts.
Original PR description
Task-6323897 Forward-Port-Of: odoo/enterprise#124233
The mail testing setup now better matches what the real server sends when edited messages include mentions. This helps prevent misleading test results and supports more reliable message editing behavior over time.
Original PR description
Before this commit, the mock of /mail/message/update_content sends "avatar_128" and "name" for every mentioned partner, where python sends _store_avatar_fields, that is the avatar access token and write_date, plus the dynamic name fields. So a test that edits a message with mentions fills the store with a key the server never sends, and misses the ones it does.
This fix makes Odoo properly clean up reusable page elements such as popups, carousels, tooltips, menus, and tabs when users leave or refresh parts of a page. It reduces browser memory growth during repeated page interactions and automated testing, improving stability without changing normal user workflows.
Original PR description
*: pos_self_order, website, portal, portal_rating, project, website_event, website_links, website_mass_mailing, website_slides, account_payment Several places create a Bootstrap 5 component…
*: pos_self_order, website, portal, portal_rating, project, website_event, website_links, website_mass_mailing, website_slides, account_payment Several places create a Bootstrap 5 component (Carousel, Modal, Dropdown, Tab, Popover, Tooltip, Collapse, Offcanvas) without ever calling .dispose() on teardown. Bootstrap keeps every instance in a page-global Map (not a WeakMap) keyed by its DOM element (see `elementMap` [1], so a missing dispose() permanently leaks the element. Three helpers centralize the fix and dedupe disposal per instance (safe even if several owners obtain the same instance, e.g. a popup surviving a builder re-render): getOrCreateBootstrapInstanceForInteraction and getOrCreateBootstrapInstanceForEditorPlugin get-or-create an instance and register its disposal on the owner's teardown, for Interaction and Plugin owners respectively; useBootstrapInstance is the Owl hook equivalent for Components. disposeBootstrapInstance disposes an instance right away (e.g. from a hidden.bs.modal handler) through the same dedup tracking, so it is never disposed twice. Mostly invisible in normal usage, but a severe leak in the JS unit test suite (thousands of mount/unmount cycles in one browser session): | Run | Scope | Memory before | Memory after | Percent | |-------------------------------|-------|--------------:|-------------:|--------:| | carousel_hook.js (16719 tests) | all | 934.5 MB | 363.2 MB | -61% | Runbot errors: - https://runbot.odoo.com/odoo/error/945770 - https://runbot.odoo.com/odoo/error/945772 [1]: https://github.com/odoo/odoo/blob/6d2fda1/addons/web/static/lib/bootstrap/js/dist/dom/data.js#L23
This update stabilizes an automated test for the website countdown feature by ensuring time is handled consistently during testing. It reduces false test failures, helping development and release checks run more reliably without changing customer-facing behavior.
Original PR description
Since revamp of the countdown [1], this test fails sometimes. This happens because the countdown schedules its renders on the exact start of the next second (1000 - Date.now() % 1000 => 000 ms), and…
Since revamp of the countdown [1], this test fails sometimes. This happens because the countdown schedules its renders on the exact start of the next second (1000 - Date.now() % 1000 => 000 ms), and because hoot uses performance.now() for timers, but Date.now() for date, which can differ by a fraction of a millisecond [2]. So unless time is frozen, we can have such an issue: - we advance time by a second - `performance.now() + offset` triggers an interval function execution - countdown uses Date.now(), which might still be on the previous second => test fails as the seconds didn't update. This is fixed by freezing time. Also, for readability we add two helpers to read hours and seconds. [1]: https://github.com/odoo/odoo/commit/2ff879a3532b97a424400cad63fd32ef05e2d7f4 [2]: https://stackoverflow.com/questions/30795525/performance-now-vs-date-now#:~:text=On%20non%2DFirefox%20browsers%2C%20Date.now()%20is%20accurate%20to%20~1ms%20and%20performance.now()%20is%20accurate%20to%20~0.1ms%20unless%20in%20certain%20cases.%20If%20you%27re%20using%20Firefox%2C%20the%20accuracy%20is%20down%20for%20both%20to%202ms.%20They%20are%20both%20extremely%20fast
The search bar now uses the same rounded styling in both Community and Enterprise editions, reducing visual inconsistencies for users. This also makes dashboard search bars match the rest of the interface and simplifies future maintenance and testing.
Original PR description
*: spreadsheet_dashboard The round styling of the search bar was defined in web_enterprise, as xpaths over web.SearchBar / web.SearchBarMenu plus two scss files, so community and enterprise had two visibly different search bars. There is not much reason for them to differ, so the enterprise look becomes the only one and is written directly on the base templates. It also removes two annoyances: hoot tests often load web without web_enterprise, so the actual styling inside tests moves even further away from reality, and xpath attribute edition always adds complexity to the code so it ends up less readable and harder to customize without issues. The dashboard search bar, a standalone template the xpaths never reached, is a good example of that so this commit also adapts its template to the unified styling.
This fixes a mismatch that caused the HTML editor to calculate text contrast differently in Community and Enterprise. Users get more consistent readable text colors, and tests now align across both editions without tying the editor to unrelated control panel styling.
Original PR description
Since https://github.com/odoo/enterprise/commit/91a97dd1b9085ba348d0ecb4479cf96422ed4168, the ContrastPlugin resolved a different background in community and in enterprise, and thus adjusted the same…
Since https://github.com/odoo/enterprise/commit/91a97dd1b9085ba348d0ecb4479cf96422ed4168, the ContrastPlugin resolved a different background in community and in enterprise, and thus adjusted the same content to a different color on each side: it read `--o-control-panel-background-color`, which enterprise now maps to `$o-webclient-background-color` (#f8f9fa) while community keeps `$o-view-background-color` (#FFFFFF). White text on white was therefore darkened to rgb(183, 183, 183) in community and to rgb(178, 178, 178) in enterprise, and the editor tests could only pass on one side. That variable was never the control panel's business: it was exposed as a CSS variable by https://github.com/odoo/odoo/commit/26a85df9df766f2f56431b491cf692488d426524 for the sole use of the plugin, at a time when it happened to be the background the editable is drawn on. Rename it to `--o-html-editor-background-contrast`, declare it in html_editor for both the backend and the frontend, and default it to the view background. The plugin no longer depends on a design decision that is not its own, and any context rendering the editor on another background can override it. The control panel gets its plain SCSS value back, as nothing was overriding the variable. The colors expected by the tests are the same again on both sides, which partially reverts https://github.com/odoo/odoo/commit/443fdc2edc017ba872b411df79f91df4afdd3951: only its test changes are undone, its website SCSS change is kept.
When an action fails, Odoo now keeps existing dialogs open instead of closing them during recovery. This prevents users from losing important pop-ups or missing error-related dialogs, improving reliability in the web interface.
Original PR description
Before this commit, clicking a notification of an inaccessible record in the messaging menu opened no dialog, and the nightly build failed on FAILED: [4/8] Tour access_inbox_records_tour -> Step…
Before this commit, clicking a notification of an inaccessible record in the messaging menu opened no dialog, and the nightly build failed on
FAILED: [4/8] Tour access_inbox_records_tour -> Step .o_dialog
.o-mail-Message-body:text(Message in inaccessible record).
Element has not been found.
This happens because the messaging menu shows the message in a dialog from the rejected promise of the action, while the action service restores the controller displayed before the failure, and `_updateUI` closes every dialog at the end of a restore. A dialog the user had opened before the failed click is closed the same way.
This only shows since "[IMP] web, project: enable test_documents_full eslint" *: the group check that commit moves to the end of a cog menu `isDisplayed` ran on every view, and its await delayed the mount of the controller, so the stack was still empty when the error arrived and the error path restored nothing.
This commit fixes the issue by keeping the dialogs open when the restore recovers from a controller error, as such a restore brings back the controller that was already displayed.
https://runbot.odoo.com/odoo/error/946461
* https://github.com/odoo/odoo/pull/284082The uninstall wizard no longer forces module cards into a fixed height, preventing tiny scrollbars when extra module information is shown. This improves readability in debug mode while keeping the normal view unchanged.
Original PR description
Before this commit, the module cards shown in the uninstall wizard had a fixed height. That height was just enough for the app icon, so as soon as a card had a bit more text than expected, the text no longer fitted and a small scrollbar appeared inside the card. This is what happened in debug mode, where the technical name of the module is displayed under its title: the extra line did not fit and every card ended up with its own tiny scrollbar. This commit removes that fixed height. The cards now simply take the height they need, which is the same as before in the normal case, and slightly taller in debug mode instead of scrolling. task-6518056 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Point of Sale now ignores barcode scanner input when staff are entering refund quantities on the ticket screen. This prevents accidental refund amounts or confusing maximum-quantity warnings caused by scanned product barcodes.
Original PR description
Steps to reproduce: - Have a paid order with a product ordered once - Open the ticket screen, select that order and its line - Scan a product barcode with a keyboard-wedge scanner Issue: "Maximum…
Steps to reproduce: - Have a paid order with a product ordered once - Open the ticket screen, select that order and its line - Scan a product barcode with a keyboard-wedge scanner Issue: "Maximum Exceeded - The requested quantity to be refunded is higher than the ordered quantity. 6 is requested while only 1 can be refunded." When the line holds enough quantity no dialog is shown at all and a refund quantity taken from the barcode is silently set. Cause: A keyboard-wedge scanner types the barcode as a burst of keystrokes. The number buffer discards such bursts by waiting barcodeService.maxTimeBetweenKeysInMs before handling the keys it collected and dropping any batch of more than two, but only when its holder asks for it with `useWithBarcode`. TicketScreen never set the flag, so its buffer handled every keystroke on its own and the digits of the barcode reached _setToRefundDetail as the refund quantity. ProductScreen, OrderSummary and PaymentScreen all set it. Fix: Set `useWithBarcode: true` on the ticket screen number buffer. Since the keys are now handled with a delay, capture the buffer before the selected order or orderline changes, so that a keystroke is applied to the line that was selected when it was typed and not to the next one. opw-6465148 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285083 Forward-Port-Of: odoo/odoo#281962
Shop search results and filter counts now use the same product information when matching customer searches. This prevents irrelevant matches from hidden webpage formatting, improving result accuracy and performance for larger catalogs.
Original PR description
The `/shop` product results and facets use different search fields. In particular, facets search raw `website_description` HTML, causing terms such as `weight` to match CSS like `font-weight` and process far more products than are displayed. Use one shared field list for both paths: - `name` - `variants_default_code` - `description_sale` - `description_ecommerce` Stop searching `default_code`, internal `description`, and raw `website_description`. opw-6391984 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283238 Forward-Port-Of: odoo/odoo#280720
When a recurring task series is ended by deleting its latest task, remaining tasks now correctly stop showing as recurring. This prevents users from seeing a misleading recurring-task option when no future tasks will be created.
Original PR description
**Problem:** Deleting one task of a recurrence suite ends the recurrence, but the tasks that stay behind keep the "Recurrent" option ticked. They look recurrent while no recurrence exists any more,…
**Problem:** Deleting one task of a recurrence suite ends the recurrence, but the tasks that stay behind keep the "Recurrent" option ticked. They look recurrent while no recurrence exists any more, so closing one of them never produces the next occurrence. **Steps to reproduce:** 1. Create a project with "Recurring Tasks" enabled 2. Create a task, tick "Recurrent" and mark it as done 3. Repeat on each generated occurrence until 3 or 4 tasks exist 4. Delete the last generated task 5. Open one of the tasks left in the suite **Current behavior:** The remaining tasks still show "Recurrent" ticked, but marking one as done creates no new occurrence and the recurring tasks smart button is empty. **Expected behavior:** Ending the recurrence should turn the "Recurrent" option off on every task that was part of it. **Cause of the issue:** `unlink` deletes the `project.task.recurrence` when the last task of the suite is removed, and `recurrence_id` is set to NULL on the other tasks by the database. Nothing resets their `recurring_task` boolean, so it stays `True` with no recurrence behind it. The two other places that end a recurrence, `write` and `action_unlink_recurrence`, already clear the flag on the whole suite. **Fix:** Aligning `unlink` with those two paths keeps a single meaning for `recurring_task`: it is only ticked while a recurrence actually exists. The suite has to be read before the recurrence is deleted, since the one2many is empty afterwards, and the tasks of the batch being deleted are left out so that no write lands on records that are about to disappear. opw-6425292 Forward-Port-Of: odoo/odoo#282535
Opening the timesheet systray from a task now pre-fills the relevant project and task without resetting any running timer. This prevents users from losing tracked time unexpectedly and keeps timesheet entries accurate.
Original PR description
Before this commit, the prefill used when the user opens the timesheet systray when his current loaded page is a task, will alter the form view in the timesheet systray to set the project and task when those fields are unset. The problem is `unit_amount` is also given to 0 and so the timer is reset due to the prefill system. This commit makes sure the `unit_amount` field is not inside the prefill data to make sure the timer is no longer reset. opw-6481443 Forward-Port-Of: odoo/enterprise#128672 Forward-Port-Of: odoo/enterprise#128531
This change fixes a memory cleanup issue in Planning and Appointment pages by properly releasing pop-ups and confirmation messages when they are no longer needed. It helps keep pages stable during continued use without changing day-to-day workflows.
Original PR description
*: planning, appointment Same page-global Bootstrap Data.elementMap leak pattern as community's carousel_hook.js fix: a Bootstrap 5 component (Modal, Toast, Tooltip) is created but dispose() is never called when the owning element tears down, so the (now detached) element stays permanently retained in memory. Fixed in planning's shift-detail Modal (no destroy() at all), planning's calendar Toast (disposed alongside the Popovers that already were), and appointment's "link copied" Tooltip - all three now go through community's new `getOrCreateBootstrapInstance` helper (@web/public/utils), which centralizes the get-or-create-and-register-cleanup pattern. Each of these is bounded to a single page-level element (unlike the original pos_self_order carousel, mounted repeatedly across thousands of tests), so no separate before/after measurement was done here.
The Enterprise search bar styling now matches the shared Odoo design instead of maintaining a separate version. This gives users a more consistent interface and reduces maintenance complexity behind the scenes.
Original PR description
The round styling of the search bar was defined here, as xpaths over web.SearchBar / web.SearchBarMenu plus two scss files, so community and enterprise had two visibly different search bars. There is not much reason for them to differ, so the enterprise look becomes the only one and is written directly on the base templates, in community. It also removes two annoyances: hoot tests often load web without web_enterprise, so the actual styling inside tests moves even further away from reality, and xpath attribute edition always adds complexity to the code so it ends up less readable and harder to customize without issues. See https://github.com/odoo/odoo/pull/285589
Card side panels now only round the outer corners, removing small visual notches where the panel meets the rest of the card. This makes card layouts, such as event date blocks, look cleaner while preserving existing image clipping behavior.
Original PR description
Before this commit, the aside of a card inherited the card's rounding on all four corners. Its right side is glued to the card's body, so the two right corners were rounded for nothing, which was visible as a notch on every aside having its own background, e.g. the date block of the event kanban cards. This commit only rounds the two left corners, using the card's own variables. The children of the aside keep inheriting these values, so images are still clipped the same way. task-6512312
Updated the WhatsApp integration so proxy requests send their required details in the format the server expects. This helps subscription checks receive the right information and avoids failed or inconsistent WhatsApp connection flows.
Original PR description
The calls to the WhatsApp proxy sent their parameters as a JSON body, which a `type='http'` route does not unpack into its arguments, so the proxy needed a decorator to read them back before `check_subscription` could see `db_uuid`. Send them as form fields instead. `requests` encodes a dict as `application/x-www-form-urlencoded` and sets the header itself, so the routes fill their arguments on their own and the decorator goes away on the proxy side. Forward-Port-Of: odoo/enterprise#129815
Self-order customers with a zero total no longer get sent to an unnecessary payment page. This makes checkout smoother for free items, fully discounted orders, or other no-payment scenarios.
Original PR description
Before this commit: -------- - Self-orders with a total amount of zero are still redirected to the payment page, which was unnecessary. After this commit: -------- - The payment step is now skipped for zero-amount self-orders, providing a smoother checkout flow. task-5106938 Forward-Port-Of: odoo/odoo#284736 Forward-Port-Of: odoo/odoo#230218
This fix makes navigation breadcrumbs visible again on portal list pages across several apps, including sales, purchases, projects, timesheets, accounting, loyalty, subcontracting, and partner assignment. Customers and portal users can more easily understand where they are and navigate back to the portal home area.
Original PR description
*=account, hr_timesheet, loyalty, mrp_subcontracting, project, purchase, sale, website_crm_partner_assign Steps to reproduce: 1. install sale 2. Create and confirm a sale order for a portal user 3.…
*=account, hr_timesheet, loyalty, mrp_subcontracting, project, purchase, sale, website_crm_partner_assign Steps to reproduce: 1. install sale 2. Create and confirm a sale order for a portal user 3. Login as a portal user 4. Open sale orders Issue: - Breadcrumbs are not visible beside the title. Cause: - After this commit https://github.com/odoo/odoo/commit/bba2fc505f5d0b4770eacc6877155b1aeda6d772 Variables are passed as attributes directly on the element, but breadcrumbs_searchbar was passed to portal_layout, but the nested portal_searchbar no longer received it. As a result, portal list pages rendered their title instead of the breadcrumb home link. Solution: - Pass breadcrumbs_searchbar directly to portal_searchbar Alternative: - An alternative would be to propagate t-call parameters to slot content in QWeb or changes the condition for breadcrumbs visibility related enterprise pr: https://github.com/odoo/enterprise/pull/118352 opw-6232899 Forward-Port-Of: odoo/odoo#266020
This fixes a display issue where default contact or user avatars could be downloaded instead of shown on screen in some environments. The generated avatar image format is now recognized consistently, so initials-based avatars appear properly across contacts, users, chatter, and Discuss.
Original PR description
**Description of the issue/feature this PR addresses:** `avatar.mixin._avatar_generate_svg()` generates an auto-initial SVG avatar for any record without a real uploaded image (used by `res.partner`,…
**Description of the issue/feature this PR addresses:** `avatar.mixin._avatar_generate_svg()` generates an auto-initial SVG avatar for any record without a real uploaded image (used by `res.partner`, `res.users`, and anything else inheriting `avatar.mixin`). The generated SVG opens with a single-quoted XML declaration: `<?xml version='1.0' encoding='UTF-8' ?>`. When this content is served via `/web/image/...`, `guess_mimetype()` needs to determine its Content-Type since it's a computed value with no stored attachment metadata. On systems where the installed `libmagic` library classifies that specific single-quoted byte pattern as `text/xml` rather than `image/svg+xml`, the wrong Content-Type reaches the browser. **Current behavior before PR:** On affected `libmagic` versions/databases, an auto-generated avatar (a contact or user with no uploaded photo) gets served with `Content-Type: application/octet-stream` (or `text/xml`) instead of `image/svg+xml`. Browsers can't render that inline as an image, so instead of showing the colored-initial avatar, the browser downloads it as an unrecognized file. This affects any place these avatars are displayed: contact/user form and kanban views, chatter message authors, Discuss, etc. Confirmed reproducible with `libmagic` 538 (`python-magic`), where the single-quoted declaration is classified as `text/xml`, while the exact same content with double-quoted attributes is correctly classified as `image/svg+xml`. **Desired behavior after PR is merged:** `_avatar_generate_svg()` now generates its markup with double-quoted attributes throughout, which is correctly sniffed as `image/svg+xml` regardless of the installed `libmagic` version. Auto-generated avatars render inline in the browser as intended. No other code depends on the exact quoting of this generated SVG - `res_users.py` and `hr_employee.py` both only assign the returned bytes to an image field without inspecting their content. Avatar fields are computed and non-stored, so nothing needs to be migrated - every record gets the corrected markup on its very next read, with no backfill required. Updated the two existing `test_avatar_mixin.py` tests that asserted the exact (single-quoted) SVG string, and added `test_generated_partner_avatar_mimetype` to assert the generated avatar is actually sniffed as `image/svg+xml`, so this can't silently regress. Ran locally: all 6 tests in `TestAvatarMixin` pass. Forward-Port-Of: odoo/odoo#285081 Forward-Port-Of: odoo/odoo#283149
This fixes portal pages so customers can once again see breadcrumb navigation next to page titles. The change improves navigation clarity across affected customer-facing areas such as appointments, helpdesk, subscriptions, field service, equity, and signing.
Original PR description
*=appointment, equity, helpdesk, planning_field_service, sale_subscription, sign Steps to reproduce: 1. install sale 2. Create and confirm a sale order for a portal user 3. Login as a portal user 4. Open sale orders Issue: - Breadcrumbs are not visible beside the title. Cause: - After this commit https://github.com/odoo/odoo/commit/bba2fc505f5d0b4770eacc6877155b1aeda6d772 Variables are passed as attributes directly on the element, but breadcrumbs_searchbar was passed to portal_layout, but the nested portal_searchbar no longer received it. As a result, portal list pages rendered their title instead of the breadcrumb home link. Solution: - Pass breadcrumbs_searchbar directly to portal_searchbar Alternative: - An alternative would be to propagate t-call parameters to slot content in QWeb or changes the condition for breadcrumbs visibility releted community pr: https://github.com/odoo/odoo/pull/266020 opw-6232899 Forward-Port-Of: odoo/enterprise#118352
This update improves the reliability of Odoo's automated tests by ensuring temporary changes made during tests are properly cleaned up. It also adds safer browser behavior in tests and makes progress bar behavior easier to extend, reducing the risk of hidden issues reaching users.
Original PR description
- https://github.com/odoo/enterprise/pull/129495 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 improves how automated tests clean up temporary changes, reducing the risk that one test affects another. It helps keep quality checks more reliable across areas such as IoT, Point of Sale, Spreadsheets, and VoIP, without changing customer-facing behavior.
Original PR description
- https://github.com/odoo/odoo/pull/284948 See commit messages for details. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fixes a visual inconsistency where some screens, such as Project Tasks, showed the old view switcher style when they copied the control panel to add extra buttons. The Enterprise styling now loads early enough so copied panels keep the intended rounded appearance, providing a more consistent interface across installed apps.
Original PR description
| //////////// | Projects view | Project tasks view | |--------|--------|--------| | Master | <img width="274" height="122" alt="image"…
| //////////// | Projects view | Project tasks view | |--------|--------|--------| | Master | <img width="274" height="122" alt="image" src="https://github.com/user-attachments/assets/c72473b4-e5dd-4c59-be9b-9be4b4a030fa" /> | <img width="362" height="127" alt="image" src="https://github.com/user-attachments/assets/2a130494-d8c9-4316-be16-d0dc00213b49" /> | | This PR | <img width="294" height="117" alt="image" src="https://github.com/user-attachments/assets/75d3d21f-6e6c-4dc9-8aca-96a9f4002015" /> | <img width="384" height="154" alt="image" src="https://github.com/user-attachments/assets/2a8c66f8-0c80-488d-a459-2e3760c3e745" /> | Some screens don't use the standard control panel directly, they make their own copy of it to add extra buttons. Project tasks is one of them. Since Commit[^1], the Enterprise styling of the view switcher was added to the control panel too late, so those copies were made before it existed and never got it. Their switcher kept the default look instead of the new rounded one. The manifest already had a rule to add the file early, but it came after the line pulling in the whole search folder. The first mention of a file wins, so that rule was silently ignored. Moving it above makes it apply. Whether it shows depends on which apps are installed: e.g `accountant` loads `web_enterprise` early and hides the problem, which is likely why it went unnoticed. [^1]: https://github.com/odoo/enterprise/commit/91a97dd1b90 task-6518773
This fix preserves the recorded cost of a tracked product lot after all items from that lot have been sold or consumed. This helps keep historical inventory valuation information accurate instead of showing a misleading zero cost.
Original PR description
Issue before this commit: ========================= When a lot-valuation-enabled product uses FIFO costing and all quantities from a lot are consumed, the lot's standard price is reset to 0. Steps to…
Issue before this commit: ========================= When a lot-valuation-enabled product uses FIFO costing and all quantities from a lot are consumed, the lot's standard price is reset to 0. Steps to Reproduce: ========================= - Install the stock_account and purchase modules. - Create a lot-tracked product and enable Valuation by Lot/Serial, set FIFO as the costing method. - Create a PO for 5 units of the product with a unit price of 5. - Receive the products and check the lot's standard price; it is set to 5. - Sell all the product quantity for that product. - Open the lot form. Observation: The lot's standard price (cost) is reset to 0. Cause of the issue: ========================= In this [PR](https://github.com/odoo/odoo/pull/276163), the FIFO valuation logic computes the standard price using: - std_price = value / quantity if quantity else 0 When the lot quantity becomes 0, the quantity used for this computation is also 0. As a result, the standard price is reset to 0 even though the lot's historical cost is still relevant. With This Commit: ========================= Keep the lot's standard price when its quantity reaches 0, instead of resetting it to 0.
Payslip totals for worked days and hours now count only paid work entries, so periods such as days outside an active contract no longer inflate totals. This gives payroll teams more accurate figures while still keeping unpaid lines visible for transparency.
Original PR description
### Purpose Fix totals (`sum_worked_days`, `sum_worked_hours`) on payslips by excluding unpaid worked days (e.g., "Out of Contract"). By updating the compute method for those fields to take account for `is_paid` lines only. Added a unit test to ensure mid-month contract totals calculate correctly. ### How to reproduce - Go to Payroll and create a contract for an employee starting in the middle of the month (e.g., 15th of the current month). - Generate a payslip for that employee for the full month. - Check the total "Worked Days" and "Worked Hours" at the top of the payslip. Before this PR: <img width="1238" height="516" alt="image" src="https://github.com/user-attachments/assets/76cfdb29-a706-481c-b07f-03aabc548e84" /> After this PR: <img width="1238" height="516" alt="image" src="https://github.com/user-attachments/assets/ca3e0ecd-fac3-4f98-b0bc-203aabb89c4b" /> task-6205747
This change rolls back a recent GIF resizing update because it caused slow performance and memory errors when pages displayed multiple GIFs. It helps keep image-heavy views, such as Kanban screens, responsive and reliable for users.
Original PR description
Revert commit d9fae40571c4f10c17fe00efc087cb25b30b85ab as it's slow on odoo.com and the call to `frame.copy()` is raising a MemoryError when loading a KanbanView with multiple gifs. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284884 Forward-Port-Of: odoo/odoo#284479
Point of Sale loyalty rewards now correctly grant a free product from a tagged product group when the cashier changes the quantity using the numpad or barcode quantities. This prevents missed promotions and ensures Buy 2 Take 1 offers behave consistently regardless of how items are entered.
Original PR description
Steps to reproduce: - create a "Buy 2 Take 1" program whose rule and reward both target a product tag containing several products - in the PoS, add one of the tagged products to the order - set its…
Steps to reproduce: - create a "Buy 2 Take 1" program whose rule and reward both target a product tag containing several products - in the PoS, add one of the tagged products to the order - set its quantity to 3 with the numpad Issue: The free product is not given. Clicking the product a third time instead of typing the quantity does give it, and so does a program whose reward is a single product. Cause: A reward whose products come from a tag is multi_product, so getClaimableRewards never computes its unclaimed quantity and the auto claim of updateRewards skips it: which product to give out is unknown. The only place claiming such a reward is addLineToCurrentOrder, which resolves it with the product that was just added. Setting a quantity does not go through it, hence the difference. Fix: Resolve the reward product the same way when auto claiming: the product of the line being worked on, or, failing that, the only reward product the order contains. The reward then follows the quantity of any of the tagged products, not only of the first one added, and the cashier is still asked when the order does not settle the choice. opw-6430385 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284777
This fix makes an internal mail test more reliable by ensuring it waits for the correct mention suggestion list instead of an unrelated status update. It helps prevent false failures in automated checks, supporting smoother releases without changing user-facing behavior.
Original PR description
Before this commit, the test "select @ mention from the suggestion list being filtered" could fail on runbot, on the check that follows the first "@": Failed to find 2 of ".o-mail-Composer-suggestion" (Timeout of 10 seconds). Found 0 instead. This happens because the test holds a render open on ImStatus, a component the member list renders as well as the composer. The composer tells the server that the user is typing, the bus sends the status back, and the member list re-renders its ImStatus with another class. The hold catches that render, the one that also brings the suggestions on screen. This commit gives the children of NavigableList an inNavigableList environment flag, and holds the render only on an ImStatus that has it. https://runbot.odoo.com/odoo/error/946282 Forward-Port-Of: odoo/odoo#285280 Forward-Port-Of: odoo/odoo#284484
Planning now calculates allocated hours correctly when multiple employees share the same shift and working schedule. This helps managers see accurate daily workload totals in the Gantt view, reducing scheduling mistakes.
Original PR description
## Steps to reproduce: - Install Planning and Employee - Create a working schedule for example 38h/week (8h,8h,8h,8h,6h) - Create two employees and assign the created working schedule to them -…
## Steps to reproduce: - Install Planning and Employee - Create a working schedule for example 38h/week (8h,8h,8h,8h,6h) - Create two employees and assign the created working schedule to them - Create a shift in planning for the two employees for a week - Notice in gantt view the total allocated hours for each day are not calculated correctly ## Cause: When calculating each cell's duration we fetch the resources' intervals while doing this here https://github.com/odoo/enterprise/blob/1851d3046682020686f517dec3c744d88a38b049/planning/static/src/views/planning_gantt/planning_gantt_renderer.js#L354-L359 we loop over the first interval and instead of pushing to the intervals we overwrite on the whole list with the interval we fetched so when it comes to the next interval it won't find any intersection so it will set the resourceIntervals to an empty array. So here https://github.com/odoo/enterprise/blob/1851d3046682020686f517dec3c744d88a38b049/planning/static/src/views/planning_gantt/planning_gantt_renderer.js#L231-L234 it will mess up the percentage calculation which will lead to wrong allocated hours numbers. ## Fix: Instead of overwriting on resourceIntervals we push to it the intervals returned to keep the intervals for each resource. opw-6316368 Forward-Port-Of: odoo/enterprise#123750
Corrects several SAF-T/FAIA report issues affecting Luxembourg audit exports, including negative tax amounts, software version length, foreign currency tax values, and invoice customer/supplier details. These fixes help businesses produce compliant audit files and reduce validation errors during tax reporting.
Original PR description
This is one of many errors fixing the FAIA report, which is the SAF-T report for Luxembourg. See PR #113316 for a list of similar PRs. ### Error 1: Negative tax amounts Auditors from Luxemborg…
This is one of many errors fixing the FAIA report, which is the SAF-T report for Luxembourg. See PR #113316 for a list of similar PRs. ### Error 1: Negative tax amounts Auditors from Luxemborg provided one Odoo user with analysis files of their FAIA xml report. The following discrepancy was present in more than 300 lines: `[TaxInformation/TaxAmount/Amount] # is negative. Only postive values are admitted. The sign is automatically determined by the corresponding CreditAmount (-) Or DebitAmount (+) on the same Line.` This discrepancy was caused by two different scenarios. The first was a negative `unit_price` line, such as a Discount product. The second was a tax with negative and positive repartition lines, such as a tax with xml ID `lu_2015_tax_AP-EC-17`. Luxembourg officials confirmed the following behavior: 1. The TaxInformation/TaxAmount/Amount element must be positive. 2. The TaxInformationTotals/TaxAmount/Amount element may be negative. 3. There may only be one TaxInformationTotals element per TaxCode in an Invoice element. This commit ensures that these conditions are met for the FAIA report. I'm not sure if the TaxInformation changes should also be applied to the base `account_saft saft_report.xml` file. ### Error 2: SoftwareVersion The SoftwareVersion element is limited to 18 characters. The relevant error from a customer's analysis file is below. Error: Value exceeds maxLength of "18". ### Error 3: CurrencyAmount The `account_saft` method `GeneralLedgerCustomHandler._saft_fill_report_tax_details_values()` does not report the amount of tax in foreign currency, instead replacing this value with the amount in company currency. No errors prompted this change; it just seems wrong on its face. ### Error 4: PR #113720 ensured that the TaxType element is always TVA. This means that the TaxType should no longer should be ignored in our example documents. ### Error 5: Schema validation failure The elements Inovice/CustomerInfo and Invoice/SupplierInfo are defined with the element `<xs:choice>` in the XSD file linked below. Only one can be present at any time, not both. https://pfi.public.lu/dam-assets/backup/FAIA/FAIA/XSD_Files.zip. note: currently the link is broken. PR #100749 allowed many parts of SAF-T code to display both customer and supplier data, including these elements. This commit ensures that the elements are mutually exclusive. opw-6344914 [Link](https://www.odoo.com/odoo/project.task/6344914) Forward-Port-Of: odoo/enterprise#129043 Forward-Port-Of: odoo/enterprise#126121
Manufacturing orders in warehouses using a 3-step production flow are now counted correctly in stock forecasts. This helps replenishment teams see incoming finished goods accurately and avoid unnecessary purchasing or production decisions.
Original PR description
### Steps to reproduce: - In the settings enable Multi-Steps Routes - Put your warehouse in manufacture in 3 steps - Create a storable product P - Create and confirm an MO for 1 unit of P - Go to…
### Steps to reproduce: - In the settings enable Multi-Steps Routes - Put your warehouse in manufacture in 3 steps - Create a storable product P - Create and confirm an MO for 1 unit of P - Go to Inventory > Operations > Procurement > Replenishment - Create a new one for P in WH/stock #### > The forecasted quantity in stock is still 0 but should be at 1 ### Cause of the issue: This is the exact use case already fixed in 85dd3369ed17b98b2ce485be04f140cf4cfa8aa3, which stamped the finished move with a `location_final_id` pointing at WH/Stock so that the move contributes to the forecast there even though its `location_dest_id` is the intermediate WH/Post-Production. That fix was reverted in practice by 42275f83dc5350822a625e19d65148e8b41ab1d4, which replaced the value with `mo.location_dest_id`: https://github.com/odoo/odoo/blob/6a56908e5febfdb4e6e0eacfb8655b092319819f/addons/mrp/models/stock_move.py#L466-L467 Its reasoning was that in a single-warehouse setup `location_dest_id` equals the warehouse stock location, so the behaviour would be unchanged. That holds in 1 and 2 steps, where the extra step is on the component side and only moves `default_location_src_id` to the pre-production location. It breaks in 3 steps, the only mode that also moves `default_location_dest_id`, to the post-production location: https://github.com/odoo/odoo/blob/6a56908e5febfdb4e6e0eacfb8655b092319819f/addons/mrp/models/stock_warehouse.py#L246-L247 and `_compute_locations` propagates it to the MO: https://github.com/odoo/odoo/blob/6a56908e5febfdb4e6e0eacfb8655b092319819f/addons/mrp/models/mrp_production.py#L334-L341 WH/Post-Production is a sibling of WH/Stock under the warehouse view location, not a child of it. Since `location_final_id` takes precedence over `location_dest_id` for the non-done part of the move chain: https://github.com/odoo/odoo/blob/6a56908e5febfdb4e6e0eacfb8655b092319819f/addons/stock/models/product.py#L331-L334 the finished move stopped being counted in the WH/Stock forecast. Why the test did not catch it: `test_3_steps_manufacturing_forecast` stayed green through the whole regression, because it scoped `virtual_available` with a `location_id` context key. `_get_domain_locations` only reads `location` and `warehouse_id`; `location_id` is silently ignored: https://github.com/odoo/odoo/blob/6a56908e5febfdb4e6e0eacfb8655b092319819f/addons/stock/models/product.py#L284-L287 The call therefore fell through to the branch scoping the forecast to every warehouse view location: https://github.com/odoo/odoo/blob/6a56908e5febfdb4e6e0eacfb8655b092319819f/addons/stock/models/product.py#L303-L309 and the warehouse view location is the common parent of both WH/Stock and WH/Post-Production. The assertion held regardless of where `location_final_id` pointed, so the test was a false positive from the start: it also passes with 85dd3369ed17b98b2ce485be04f140cf4cfa8aa3 fully reverted. Using the `location` key makes it fail without the fix and pass with it. ### Fix: Neither fix proposition was right on its own; each one was correct only in its own scenario. The`mo.warehouse_id.lot_stock_id` resolves the warehouse from the components, so it points at the wrong warehouse as soon as the finished product is produced for another one. `mo.location_dest_id` is the post-production location as soon as the warehouse manufactures in 3 steps, so it drops the quantity from the forecast of the manufacturing warehouse itself. What separates the two is not the warehouse but whether the destination is a transit step. In 3 steps the finished product only reaches the stock through the post-production push rule: https://github.com/odoo/odoo/blob/6a56908e5febfdb4e6e0eacfb8655b092319819f/addons/mrp/models/stock_warehouse.py#L57 so the final location is the stock of the warehouse owning that destination. Any other destination is already final and is kept as is, which leaves cross-warehouse MOs and destinations set to a sub-location of the stock untouched. The rule's destination is read rather than `warehouse.lot_stock_id` because a push move takes its destination from the rule and not from the operation type: https://github.com/odoo/odoo/blob/6a56908e5febfdb4e6e0eacfb8655b092319819f/addons/stock/models/stock_rule.py#L256-L260 so the forecast stays correct when the store step is reconfigured to land somewhere else than the warehouse stock. The rule is looked up on `pbm_route_id` by its `picking_type_id` instead of through `warehouse.sam_rule_id`, because that field is no longer set. It used to be an entry of `_generate_global_route_rules_values`, and it is that entry which made the generic warehouse machinery create the rule and store it back on the warehouse: https://github.com/odoo/odoo/blob/6a56908e5febfdb4e6e0eacfb8655b092319819f/addons/stock/models/stock_warehouse.py#L403-L410 11e69870db1c49d9a6af79ffd263e4e162b34b6b removed it when the post-production step stopped being a pull rule on the Manufacture route and became a push rule generated from `get_rules_dict`. Only the field declaration was left behind, and nothing writes it any more: https://github.com/odoo/odoo/blob/6a56908e5febfdb4e6e0eacfb8655b092319819f/addons/mrp/models/stock_warehouse.py#L21-L22 so reading it would silently give an empty recordset. The lookup is not delegated to `_get_push_rule` to avoid a search per finished move. opw-4882390 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285185 Forward-Port-Of: odoo/odoo#283234
This fix ensures user group checks work correctly when the same group is referenced by more than one XML identifier. It prevents access or permission checks from returning inconsistent results depending on which valid group identifier is used.
Original PR description
A group can be identified by multiple xmlids. We add support to provide a list of "refs" to the `SetDefintions` object.
Reproductible issue:
```
demo = self.env["res.users"].browse(5)
demo.has_group("accountant.group_account_user") # False
demo.has_group("account.group_account_user") # True
assert self.env.ref("accountant.group_account_user") == self.env.ref("account.group_account_user")
```
task-6471260
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#285153
Forward-Port-Of: odoo/odoo#284866Calendar invitation files now include the meeting video link in a standard URL field. This helps recipients and calendar apps surface the correct online meeting link more reliably.
Original PR description
Add the meeting's videocall_location as a URL property in generated iCalendar (.ics) invitation files. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283934 Forward-Port-Of: odoo/odoo#283562
Belgian payroll meal voucher reports no longer crash when an employee has no meal voucher amount for a month. The report now keeps the employee line with a zero total, helping payroll teams complete reporting even during full-month sick leave or corrected payslips.
Original PR description
**Steps to reproduce:** - In a belgium company - Put an employee in sick time off during a whole month - Generate a mealvoucher report for this month Another steps to reproduce: - Create a payslip for an employee that has mealvoucher input > 0 - Mark the payslip as paid - Put the mealvoucher input at 0 for the employee - Correct the payslip - Generate a mealvoucher for the payslip month **Current behavior:** Crash **Expected behavior:** The line should show lorie poiret in the report with 0 total. It is debatable to either filter out the 0 line from the report or not as it is not a standardized report and that all providers has their interpretation. We decided to show it. task-6487876 Forward-Port-Of: odoo/enterprise#128716
Changing a project’s visibility no longer fails when the project’s document folder includes shortcuts. This ensures access settings can be updated as expected while still preventing direct access changes on shortcut-only documents.
Original PR description
Changing a project's visibility fails when its documents folder contains a shortcut. The visibility change is never applied and the following error is raised: "You can not update the access of a…
Changing a project's visibility fails when its documents folder contains a shortcut. The visibility change is never applied and the following error is raised: "You can not update the access of a shortcut, update its target instead." ### Reproduction steps - Create a project and add a document to its folder. - Create another document outside the project's folder. - Create a shortcut to that document in the project's folder. - Change the project's visibility. ### Cause Changing a project's visibility updates the access rights of its folder and documents together. The shortcut access check is meant to reject operations performed only on shortcuts. However, reading `shortcut_document_id` on a recordset returns the shortcut targets found across that recordset. Therefore, the presence of a single shortcut makes the check reject the whole operation. This prevents regular documents and the project folder from having their access updated. ### Fix Only reject access updates when all records involved are shortcuts. This preserves the protection against changing shortcut access directly while allowing project access updates to include shortcuts alongside regular documents and folders. opw-6472637 Forward-Port-Of: odoo/enterprise#129588 Forward-Port-Of: odoo/enterprise#128756
This fix closes a gap that allowed a newly created fiscal year to fully contain an existing fiscal year without being flagged as overlapping. Businesses get more reliable accounting period setup and avoid conflicting fiscal year definitions that could affect reporting.
Original PR description
Before this commit: - The current constraint for overlap check allows if we define a new, larger fiscal year that completely swallows an existing smaller one (e.g., creating Aug 2025 - Nov 2026 when Sept 2025 - Oct 2026 already exists). After this commit: - The constrain domain was changed to consider the above missed case. no task Forward-Port-Of: odoo/enterprise#128942
Inventory users can now validate dropship transfers for products using average costing when landed costs are enabled. This prevents an access error that blocked normal sales and purchasing workflows for affected products.
Original PR description
# How to reproduce - Activate the stock_landed_costs module - Enable Dropshipping - Create a product with : - Category : - Costing Method : AVCO - Inventory Valuation : Perpetual - Routes : Dropship…
# How to reproduce - Activate the stock_landed_costs module - Enable Dropshipping - Create a product with : - Category : - Costing Method : AVCO - Inventory Valuation : Perpetual - Routes : Dropship - Atleast one vendor - Create a SO for that product - Confirm the SO & then Confirm the associated PO - Login as an user with "User" rights for Inventory - Try to validate the Dropship transfer # The issue You get an access error. If the same flow is done with a product with a Standard Price costing method, then the Dropship is properly validated # Cause When validating the Dropship, we'll call `_action_done` on the moves. This will trigger an update of the standard price of the product : https://github.com/odoo/odoo/blob/60bc7ae38e335958589c172df88e059bf0738cac/addons/stock_account/models/stock_move.py#L177 https://github.com/odoo/odoo/blob/60bc7ae38e335958589c172df88e059bf0738cac/addons/stock_account/models/stock_move.py#L345-L349 Since we're in avco, this will run the `_run_average_batch` method : https://github.com/odoo/odoo/blob/60bc7ae38e335958589c172df88e059bf0738cac/addons/stock_account/models/product.py#L675 That will fetch the value of each moves. For the Dropship moves, it'll do so by calling the `_get_value()` method : https://github.com/odoo/odoo/blob/60bc7ae38e335958589c172df88e059bf0738cac/addons/stock_account/models/product.py#L486 This method will compute the value of the move, notably by using the associated landed costs : https://github.com/odoo/odoo/blob/60bc7ae38e335958589c172df88e059bf0738cac/addons/stock_account/models/stock_move.py#L431 https://github.com/odoo/odoo/blob/60bc7ae38e335958589c172df88e059bf0738cac/addons/stock_landed_costs/models/stock_move.py#L14 Now the issue is that this computation calls `_read_group` on 'stock.valuation.adjustment.lines' that are retricted to inventory administrators : https://github.com/odoo/odoo/blob/60bc7ae38e335958589c172df88e059bf0738cac/addons/stock_landed_costs/models/stock_move.py#L11 https://github.com/odoo/odoo/blob/5f6fb63d5d7585805642c702d096b2f882e73761/addons/stock_landed_costs/security/ir.model.access.csv#L4 # Proposed solution Get the value of the move in sudo like previously done in the flow : https://github.com/odoo/odoo/blob/60bc7ae38e335958589c172df88e059bf0738cac/addons/stock_account/models/stock_move.py#L314 opw-6323645 Forward-Port-Of: odoo/odoo#284251 Forward-Port-Of: odoo/odoo#273102
Swiss payroll employee records now show only Switzerland-specific certificate options instead of mixing in generic employee certificate values. This reduces confusion for payroll teams and helps users select the correct certificate type for Swiss localization workflows.
Original PR description
The certificate field on the employee model was being extended by the swiss localization to add the swiss-specific certificates. This was done using selection_add on the field which was causing the selection to also show the original values defined on the base employee model. We don't want to see the original values but only the swiss ones when we operate in the swiss localization. At the same time, we can't just override the field (without using selection_add) because a warning is triggered. Other possible solustions like using the result of a function or changing the type of the field to Many2one to use a domain are either not working on a record-per-record basis or not stable compliant. The only working solution for stable is to keep the selection_add working and filter the results in the views using the filterable_selection widget. Task: 5948460 Forward-Port-Of: odoo/odoo#250046
The accounting dashboard now shows the Import File button for credit card and cash journals, not just bank journals. This makes file-based transaction imports available wherever the journal is configured to use them, reducing confusion for users managing non-bank payment accounts.
Original PR description
The "Import File" button on the dashboard card only shows up for bank journals. Credit card journals are treated the same way as bank journals pretty much everywhere else: the dashboard card itself,…
The "Import File" button on the dashboard card only shows up for bank journals. Credit card journals are treated the same way as bank journals pretty much everywhere else: the dashboard card itself, the statements list, the "Transaction Feeds" setting on the journal form (where you can pick the file import option), and even `create_document_from_attachment` in this module, which already accepts them. So you end up with a credit card journal set to import files but nothing on its card to actually do it, and people assume the feature is simply not there. Show the button on credit card journals too. Steps to reproduce: - Install account_bank_statement_import_csv (or any other import format) - Create a "Credit Card" journal and set its Transaction Feeds to the file import option - Go to the Accounting dashboard - The bank journal card has an "Import File" button, the credit card one doesn't --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/enterprise#129546
This fixes an issue where retrying a rejected simplified Saudi e-invoice could fail because the QR code was missing. The system now recreates the QR code from the invoice submission data during retry, helping businesses resubmit rejected invoices without errors while keeping normal QR display rules unchanged.
Original PR description
- When a simplified (B2C) invoice is rejected by ZATCA and subsequently retried, its state remains rejected. The QR code computation therefore returns an empty value for the rejected invoice, as the computation is primarily intended for the post-EDI state. During the retry, this results in a traceback when the QR code is applied to the XML. - Regenerate the QR code directly from the submission data when preparing a new B2C XML, instead of relying on the state-dependent QR code field. This preserves the existing QR visibility rules for the final invoice. task-6485555 Forward-Port-Of: odoo/odoo#284733 Forward-Port-Of: odoo/odoo#283534
This fixes an access problem that could prevent Belgian payroll leave allocations from being validated correctly. The change ensures the validity check has the required permissions, reducing interruptions for HR payroll workflows.
Original PR description
A sudo was missing in the check of the validity of the allocation. Forward-Port-Of: odoo/enterprise#129652
This fix ensures that views edited in Odoo Studio keep characters from languages such as Chinese and Arabic readable instead of converting them into code-like symbols. It improves the editing experience for multilingual users without changing business workflows.
Original PR description
Currently, when we combine the arch for the base views in the xml editor, we encode the text using the etree default of us-ascii. This causes special characters (chinese, arabic, etc.) to be converted to html codes. To rectify this issue, we set the encoding of the string to unicode. ### Before <img width="739" height="334" alt="before" src="https://github.com/user-attachments/assets/ad77fc47-08a0-42ed-b34b-d033779e9fc2" /> ### After <img width="673" height="334" alt="after" src="https://github.com/user-attachments/assets/1dae36c6-46d1-4189-b448-790aee18f319" /> opw-6325841 Forward-Port-Of: odoo/enterprise#128336
This change corrects how Odoo handles static file paths on Windows. It prevents path separator differences from breaking access to static resources, helping Windows deployments behave consistently.
Original PR description
In commit 31aad6c, path normalization was added which also resulted in `/` being converted into `\` on Windows. There the `path.split('/')` did not work.
This commit changes the `'/'` to `os.sep` to fix the issue.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#285265
Forward-Port-Of: odoo/odoo#285216French VAT report submissions now handle account holder names longer than the official XML limit by splitting them into two fields. This helps prevent filing errors when a company or holder name exceeds 35 characters.
Original PR description
The XSD for XML-EDI does not allow strings longer than 35 for TitulaireDesignation This commit splits the holder name in 2 parts when it is more than 35 characters task-6476440 Forward-Port-Of: odoo/enterprise#129513 Forward-Port-Of: odoo/enterprise#128239
Resumed shopping carts now recalculate the selected delivery cost after product prices are refreshed at checkout. This prevents customers from incorrectly keeping free shipping when an updated order total no longer qualifies, while preserving selected pickup locations for click-and-collect orders.
Original PR description
Steps to reproduce ================== 1. Configure a delivery method with free shipping above a threshold 2. Add a product to the cart above that threshold, select the delivery method and leave the…
Steps to reproduce ================== 1. Configure a delivery method with free shipping above a threshold 2. Add a product to the cart above that threshold, select the delivery method and leave the cart unfinished 3. Lower the product price below the threshold 4. Recover the cart and confirm the order from /shop/checkout => The product prices are refreshed, but shipping stays free although the new total is below the threshold. Root cause ========== Since [1], nothing re-rates the carrier after /shop/confirm_order refreshes the cart prices: the delivery method is selected before the confirmation. In 17.0, the payment page auto-clicked the selected carrier on load, which re-rated the shipping cost and masked the issue. Fix === Re-rate the selected delivery method in `shop_confirm_order` after the prices have been recomputed, as `_cart_update` already does. [1]: https://github.com/odoo/odoo/commit/8e2b6cede55b51f7ccdbe7601aa7e6035fd6f9fe opw-6383849 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284606 Forward-Port-Of: odoo/odoo#276905
Fixed an issue that could prevent the Assets list from opening when older or inconsistent analytic distribution data referenced deleted accounts. Users can now access the list view without getting stuck in an error loop, while the invalid underlying data remains unchanged for later correction.
Original PR description
Issue - If there are any account.asset records with analytic distributions with accounts that do not exist, it causes a recursive traceback when opening the list view of the `account.asset` model. The issue stems from `jsonToData` attempting to save the distributions json via the `save` call, where one (or multiple) accounts are non existent, which in turn runs `jsonToData` after refetching via the `load` call - overwriting `record.data` with the original, still-corrupt JSON. This creates a loop with no exit condition. Solution - In the Assets list every row is readonly, so `save()` is never reached, so `root.load()` never fires, so there is no reload to re-read the corrupt JSON. Makes the list accessible, even though the JSON values for the `analytic_distribution` are invalid. opw-6500446 Forward-Port-Of: odoo/odoo#285527 Forward-Port-Of: odoo/odoo#285381
This fix prevents custom website buttons from losing their gradient background when a user changes the button text color. It helps website editors keep the intended button design without needing to reapply styling.
Original PR description
Steps to Reproduce : 1. Go to Website → Edit Mode 2. Add a snippet with button 3. Click on button and change its type to : " Custom" 4. Apply the gradient type color in fill color option 5. Apply any…
Steps to Reproduce : 1. Go to Website → Edit Mode 2. Add a snippet with button 3. Click on button and change its type to : " Custom" 4. Apply the gradient type color in fill color option 5. Apply any color in text color option 6. You will notice that the gradient type color in fill color option is removed. Problem: Since [this commit][1] new button style options have been added to the sidebar. If one changes the style of a button to custom, changes the background to gradient, and tries to change the text color, the background gradient is removed. Cause: Whenever a gradient is added either to text or as a background, it is applied as a background image. In the case of a text gradient, an additional class, `text-gradient`, is applied for correct styling. Once a change to either color or background/fill is applied that is not a gradient color change, the background image of the element would be reset to nothing. This is the result of [this line][2] from a [previous commit][3]. In the case of a button, this meant changing the font color would reset the background. That is not the desired outcome. The flaw was only discovered once new options were added to change non-text/font elements' backgrounds to gradient. Solution: An additional check has been added to see if the element being edited is text. If so, and it's a gradient style being changed, we remove the background image. Otherwise it is kept so that the button case from above is resolved. [1]: https://github.com/odoo/odoo/commit/2bf1db001b195480b963b338583c170aa1c009a3 [2]: https://github.com/odoo/odoo/blob/8e0845712f462ecfafd2176406dcbafc869a5564/addons/html_editor/static/src/main/font/color_plugin.js#L575 [3]: https://github.com/odoo/odoo/commit/8e0845712f462ecfafd2176406dcbafc869a5564 task-6247134 Forward-Port-Of: odoo/odoo#285063 Forward-Port-Of: odoo/odoo#279070
The Swedish tax report now shows Field 42 amounts as positive when appropriate, instead of incorrectly displaying them as negative. This helps Swedish companies review and submit tax reporting figures with the correct presentation.
Original PR description
**Steps to reproduce:** - Install the `l10n_se` module and switch to a SE Company. - Navigate to Invoicing > Configuration > Taxes. - Create a tax and set the tax grid to `se_42`. - Create and…
**Steps to reproduce:** - Install the `l10n_se` module and switch to a SE Company. - Navigate to Invoicing > Configuration > Taxes. - Create a tax and set the tax grid to `se_42`. - Create and confirm an invoice for a Swedish customer using this tax. - Navigate to Reporting > Tax Report. - Check the amount of `Fält 42` under `Block E`. **Observation:** The `Fält 42 – Övrig försäljning m.m.` field shows the amount as negative instead of positive. **Root Cause:** At [1], the `se_42` formula is missing the negative sign. These lines were missed by the `tax_tag_invert` revamp done in https://github.com/odoo/odoo/commit/17a6117ed88c29b5bc4db0c872bcdbc109a7d98b. **Fix:** This commit adds the missing negative sign to the `se_42` formula, ensuring that the amount for `Fält 42` is displayed as positive in the Swedish tax report, similar to [2]. [1]: https://github.com/odoo/odoo/blob/a56038c97e807388772ccc3a794cf0bf658a2076/addons/l10n_se/data/account_tax_report_data.xml#L356-L368 [2]: https://github.com/odoo/odoo/commit/b8125f38e80c1977eedda5fc6b9466ece5e9fd89 opw-6457529 Forward-Port-Of: odoo/odoo#281925
This update prevents invoice printing from failing when an Argentine company's partner record contains a VAT number that is valid in another country but not a valid Argentine CUIT. It improves reliability for Argentine localization users by allowing invoices to print instead of showing an error.
Original PR description
When printing an invoice, a traceback will occur if the company's partner has an invalid CUIT. Steps to reproduce the error: - Install ``l10n_ar_edi`` module with demo data - Switch to ``(AR)…
When printing an invoice, a traceback will occur if the company's partner has an invalid CUIT. Steps to reproduce the error: - Install ``l10n_ar_edi`` module with demo data - Switch to ``(AR) Exento`` Company - Go to Invoicing > Configuration > Journals > Open ``Ventas Preimpreso`` journal > ARCA POS System: ``Electronic Invoice - Web Service`` > Save - Create a new invoice with ``ADHOC SA`` partner > Confirm the invoice - Open the ``(AR) Exento`` partner and set the VAT to ``BE0477472701`` - Open the Invoice > print Traceback: ```py ValueError: invalid literal for int() with base 10: 'BE0477472701' ``` After this [commit], companies outside the EU can use European VAT numbers. Consequently, an Argentine partner can have a CUIT number such as ``BE0477472701``, which is valid as a Belgian VAT number but not as a CUIT. When printing the invoice, the ``l10n_ar_vat`` field is computed from the partner's VAT and its value is passed to ``int()``, causing a traceback at the following line: https://github.com/odoo/enterprise/blob/d55486866d09f8aa87c2003dab722cfa323068b4/l10n_ar_edi/models/account_move.py#L138 [commit]: https://github.com/odoo/odoo/commit/a2afe3292e1cd0a4f339dc47707e469653d13ea0 Enterprise PR: https://github.com/odoo/enterprise/pull/127820 sentry-7666042143 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284880 Forward-Port-Of: odoo/odoo#282454
Invoice printing in Argentina localization now avoids crashing when a company partner has an invalid CUIT tax ID. This helps users complete invoice printing more reliably and prevents an unexpected error message in a common accounting workflow.
Original PR description
When printing an invoice, a traceback will occur if the company's partner has an invalid CUIT. Steps to reproduce the error: - Install ``l10n_ar_edi`` module with demo data - Switch to ``(AR)…
When printing an invoice, a traceback will occur if the company's partner has an invalid CUIT. Steps to reproduce the error: - Install ``l10n_ar_edi`` module with demo data - Switch to ``(AR) Exento`` Company - Go to Invoicing > Configuration > Journals > Open ``Ventas Preimpreso`` journal > ARCA POS System: ``Electronic Invoice - Web Service`` > Save - Create a new invoice with ``ADHOC SA`` partner > Confirm the invoice - Open the ``(AR) Exento`` partner and set the VAT to ``BE0477472701`` - Open the Invoice > print Traceback: ```py ValueError: invalid literal for int() with base 10: 'BE0477472701' ``` The issue occurs because when the partner's identification type is CUIT, At [1] ``_run_check_identification()`` method does not include partners whose identification type has ``is_vat=True``. As a result, CUIT is not validated by ``_run_check_identification()`` method in ``l10n_ar`` module at [2]. So, partner's ``l10n_ar_vat`` field can be computed as ``BE0477472701``. Passing this value to ``int()`` raises the traceback during invoice printing at below line. https://github.com/odoo/enterprise/blob/d55486866d09f8aa87c2003dab722cfa323068b4/l10n_ar_edi/models/account_move.py#L138 [1]:https://github.com/odoo/odoo/blob/c2a39085ba0fbcf8a0e6a55228191e764499caea/addons/l10n_latam_base/models/res_partner.py#L24-L30 [2]:https://github.com/odoo/odoo/blob/c2a39085ba0fbcf8a0e6a55228191e764499caea/addons/l10n_ar/models/res_partner.py#L55-L65 Community PR: https://github.com/odoo/odoo/pull/282454 sentry-7666042143 Forward-Port-Of: odoo/enterprise#129449 Forward-Port-Of: odoo/enterprise#127820
Point of Sale preparation tickets now reprint correctly when an order includes combo products. This prevents silent printing failures in kitchen or preparation workflows, helping staff recover tickets reliably when needed.
Original PR description
Steps to reproduce: --- - Configure a Point of Sale with a preparation printer whose product categories contain the products of a combo. - Add the combo to an order and send it to preparation. - Try to reprint the order. Issue: --- - Nothing is printed for orders containing a combo, without any error being shown. Fix: --- - Store the combo children of a preparation change as plain ids and match the printer categories on those ids. task-6472281 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282663
Fixed an issue where commission plan calculations could fail when the same salesperson had multiple assignment rows in an overlapping plan. The system now checks each assignment separately, preventing crashes and ensuring overlapping plans are detected correctly.
Original PR description
Version: 19.4 Steps to reproduce: - Open the commission plans list with demo data - Open a plan whose salesperson has duplicate assignment rows in an overlapping plan Issue: When calculating other_plans, the code assumed each salesperson had only one assignment in an overlapping plan. It used filtered() and directly accessed date_from .If the salesperson was assigned multiple times in the same plan, filtered() returned multiple records, which caused the error and crashed the calculation. Fix: Loop over all matching rows one at a time. If any row's date range overlaps with the current assignment, flag the plan and stop. This avoids the multi record access while correctly detecting all overlap cases. Task ID: 6302927 Forward-Port-Of: odoo/enterprise#120576
Romanian SAF-T (D406) exports now use the required file version 2.0 instead of 2.4.8. This helps ensure generated declaration files match the expected regulatory format and reduces the risk of submission issues.
Original PR description
**Steps to reproduce:** - Install the `l10n_ro_saft` module and switch to the RO Company. - Navigate to Accounting > Reporting > General Ledger. - Click the gear icon > SAF-T (D406 Declaration). - Open the generated XML file and check the `AuditFileVersion` node. **Observation:** The `AuditFileVersion` node is set to `2.4.8`. **Expected behavior:** The `AuditFileVersion` node should be set to `2.0` (confirmed with the PO [1]) **Root Cause:** At [2], the `file_version` value is incorrectly set to `2.4.8` instead of `2.0`. [1]: https://www.odoo.com/mail/message/1144385840 [2]: https://github.com/odoo/enterprise/blob/ce2ad80c91aea27b143a80018aa73ed10d16cdbe/l10n_ro_saft/models/account_general_ledger.py#L179-L183 opw-6452918 Forward-Port-Of: odoo/enterprise#127935
Fixed an issue where regular timesheet users could lose access to Assistant Rules when Billing Rate Indicators were turned off. The Timesheets configuration menu now stays visible for users who need assistant-related settings, reducing confusion and avoiding the need for debug mode.
Original PR description
Steps to reproduce --- 1. Install sale_timesheet_enterprise. 2. Go to Timesheets > Configuration > Settings (as Admin). 3. Disable the "Billing Rate Indicators" setting and enable timesheet…
Steps to reproduce --- 1. Install sale_timesheet_enterprise. 2. Go to Timesheets > Configuration > Settings (as Admin). 3. Disable the "Billing Rate Indicators" setting and enable timesheet assistant. 4. Log in as a normal user with "Timesheets > Own timesheet" access. 5. Open the Timesheets app. Issue --- The "Configuration" menu is completely hidden. The regular user cannot access the "Assistant Rules" menu unless they turn on debug mode. Cause --- When the billing rates feature is turned off, the _load_menus_blacklist function hides the Enterprise Configuration menu. The logic used an and condition, meaning the menu was only kept visible if the user was an Assistant AND had Manager/Admin rights. This locked out standard users. Fix --- Change the blacklist condition. Allow the Enterprise Configuration menu to stay visible if the user needs it for the Assistant feature (when UoM is not Days), OR if the user is a Manager/Admin. References to check other issues https://github.com/odoo/enterprise/pull/120609 https://github.com/odoo/enterprise/pull/117984 task - 6470183 Forward-Port-Of: odoo/enterprise#128727 Forward-Port-Of: odoo/enterprise#128096
The UAE audit file reporting module now opens the company details form correctly from the General Ledger warning. This prevents an error that blocked users from completing missing company information during accounting report review.
Original PR description
Currently, an error occurs when trying to fill in the company details from the General Ledger. Steps to Reproduce: - Install `l10n_ae_faf` with demo data. - Switch to the `AE Company`. - Go to…
Currently, an error occurs when trying to fill in the company details from the General Ledger. Steps to Reproduce: - Install `l10n_ae_faf` with demo data. - Switch to the `AE Company`. - Go to `Accounting` > `Reporting` > `Ledgers` > `General Ledger`. - Click on `your company` in the company details warning. `AttributeError: The method 'account.report.action_fill_company_details' does not exist` In this commit, the company details warning was added to the l10n_ae_faf module, similar to account_saft. However, the action_fill_company_details method is only defined in account_saft, which is not a dependency of l10n_ae_faf. Therefore, when the user clicks on "your company" to open the company form [1], the method is not available and an error is raised. This commit ensures that action_fill_company_details is added to l10n_ae_faf so that clicking on `your company` opens the company form, as it does in account_saft. [this commit]: https://github.com/odoo/enterprise/commit/dffc4412df42507457810a0895be3b8f4dc7ec3f [1]- https://github.com/odoo/enterprise/blob/c8c2f13b7fd17e215044fc62774f2b4a378aaf8c/l10n_ae_faf/static/src/components/general_ledger/filters/warnings.xml#L3-L10 sentry-7676719103 Forward-Port-Of: odoo/enterprise#128327
This fix prevents a shopper's personal contact name from being replaced by their company name when they enter a valid VAT number during checkout. It keeps customer and company records correctly separated, improving order accuracy and customer data quality.
Original PR description
Steps to produce: --- - Install website_sale module without demo. - Create a new product and publish it. - From the incognito, go to shop and add that product to cart. - While doing checkout > fill…
Steps to produce: --- - Install website_sale module without demo. - Create a new product and publish it. - From the incognito, go to shop and add that product to cart. - While doing checkout > fill the address form. - Add the all details including the company name and valid VAT. (ex. BE0477472701) - Submit the form. Issue: --- - When a public or guest user submits a new address with both a contact name and a company name along with a valid VAT number, the contact's name was being overwritten with the company name. Root cause: --- - The _compute_is_company heuristic in res.partner automatically sets is_company=True for partners with valid VAT. In [commit] `_create_or_update_address`, the condition `elif partner_sudo.is_company:` was designed to rename existing companies, but incorrectly caught newly created individuals marked as companies due to VAT, causing their name to be overwritten instead of creating a parent company. Solution: --- - Replaced the is_company check with explicit conditions: the partner has no parent_id, has contact-type child_ids. - This ensures the rename-company branch only fires for actual company heads that the logged-in user belongs to, not for individuals that happen to have is_company=True due to a valid VAT. [commit]: https://github.com/odoo/odoo/commit/8f3a32170c842f5f42edc79bf8620276f0da7be4 opw-6356772 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285495 Forward-Port-Of: odoo/odoo#275044
This fixes an issue where text entered in the Translation dialog could disappear after the user dragged the dialog window. Users can now move the dialog without losing unsaved translation changes, reducing rework and confusion.
Original PR description
Step to reproduce: - have atleast two language and install sale - open any product, hover over product, and click on Translation button - Enter a value for one of language - drag the dialog Observation: - we lose the data, we just entered and fallback to original data Cause: - Inputs used `t-att-value="term.value"`, bound to original data. Since this content is passed to Dialog via slot, it is rendered/patched as part of Dialog's render cycle, - Dragging updates Dialog's state, triggering a patch that re-evaluated the slotted template and reset input values (which comes from `term.value`) Fix: - bind value to `updatedTerms[term.id] ?? term.value` so edits survive patches triggered by the parent Dialog opw-6431521 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284890 Forward-Port-Of: odoo/odoo#283514
This fixes activity filters so "today" is based on the user's local calendar date instead of UTC. Users in time zones ahead of UTC will no longer see activities due today incorrectly listed as future activities for part of the day.
Original PR description
#### Description of the issue: Activity filters using context_today() bucket against the UTC date instead of the user's local date, off by one for part of the day. Partial revert of #265250 (e048bb5), scoped to PyDate: UTC getters are right for PyDateTime, wrong for a calendar day. #### Current behavior before PR: A Perth (UTC+8) user finds an activity due today under "Future Activities" from 00:00 to 08:00 local, while the chatter labels the same activity "Today". #### Desired behavior after PR is merged: context_today(), today and current_date return the user's local calendar day, so filters agree with the chatter. PyDateTime and PyTime keep the UTC getters; now and time.strftime() are unchanged. opw-6415985 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281453 Forward-Port-Of: odoo/odoo#278761
This update restructures how Factur-X invoice export files are generated, replacing the previous template-based approach with a more structured XML-building process. The change is mainly internal and should make the export logic easier to maintain and test without changing day-to-day user workflows.
Original PR description
*= account_edi_ubl_cii_tax_extension, l10n_account_edi_ubl_cii_tests. Refactoring of the export of factur-x. The export now relies on a dict of nodes, and uses the function `dict_to_xml` to generate the xml instead of relying on a qweb template. task-5999127 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#261572
This update organizes how Odoo records describe the information they carry in Mail and Live Chat. It makes the code easier to understand and maintain, reducing the chance of future inconsistencies without changing day-to-day user behavior.
Original PR description
Before this commit, four fields are written on records whose model never declares them: the only way to know a record holds them is the python that sends the value, or the component that reads it. This commit declares them with the other fields of their model. https://github.com/odoo/enterprise/pull/129826
This update reorganizes how AI chat and VoIP contact information is declared so the right data is available across all relevant Odoo interfaces. It helps keep chat, live chat embeds, and contact search behavior consistent without adding new user-facing features.
Original PR description
Enterprise counterpart of "[REF] mail, im_livechat: declare the fields a record holds". voip declares res.partner's phone_formatted, which _store_voip_fields sends and the contact search reads. ai and ai_app declare theirs in models that only the backend bundle loads, while their python sends the values to every frontend. Those models move under discuss/core/common, which the public, chatter and livechat embed bundles carry, and the session's user input request is declared on the common ai.session. https://github.com/odoo/odoo/pull/285622
This update modernizes internal parts of the Documents app as part of Odoo's Owl 3 migration. It replaces deprecated technical hooks so the app stays compatible with upcoming platform changes, with no expected change to day-to-day user workflows.
Original PR description
As part of the Owl 3 migration, replace deprecated onWillRender hooks with the appropriate Owl 3 alternatives.
This update improves how website editor components check the information they receive, restoring validations after a framework migration. It also makes the Animate Text toolbar option behave consistently with other toolbar actions when it should be disabled.
Original PR description
This commit replaces the remaining `static props` declarations with the `useProps` hook, so that these components validate their props again. Since the migration to owl3, a component's schema is declared as an instance field through `useProps`, and `static props` is no longer read by the framework. The compatibility layer gives every component a catch-all `this.props`, so these declarations kept documenting props that nothing validated, and that stayed readable even when undeclared. This refactoring converts them all, aligning both modules with the rest of the codebase and preparing for the removal of the compatibility layer.