Tuesday, September 8, 2026
133 changes · master
New functionality added to Odoo
Turkish companies can now respond to received e-Dispatches directly from Odoo instead of manually using the Nilvera portal. The new workflow records received, rejected, missing, or excess quantities and follows up automatically to retrieve finalized documents from GIB.
Original PR description
A Turkish company receiving an e-Irsaliye has to tell GİB what it got: how much arrived, how much was rejected and why, and whether anything was short or in excess. Odoo could import a received…
A Turkish company receiving an e-Irsaliye has to tell GİB what it got: how much arrived, how much was rejected and why, and whether anything was short or in excess. Odoo could import a received e-Dispatch but not answer one, so the reply had to be filed by hand on the Nilvera portal. This module bridges l10n_tr_nilvera_edispatch and quality_control with a Unit Count control point, restricted to receipts of Turkish companies and to one point per operation type, since a dispatch is answered once. Its check carries one line per stock move, holding the received, rejected, missing and excess quantities and a rejection reason. Passing or failing it writes the counted quantities back onto the moves. The answer goes to Nilvera as an AcceptAll when every line arrived complete, and as DespatchAnswerLines otherwise. Its GİB document number is built from the Quality Control Point sequence prefix, the receipt's year and the check's number, and kept on the receipt so a retry re-uses the number Nilvera may already hold. An unknown serie is registered and the send retried once. Two hourly crons follow the answer up, on the receipts the company answers and the deliveries its customers answer, and pull the signed XML and PDF once GİB settles it. task-5419976
Adds India-specific Schedule III Balance Sheet and Profit and Loss reports so companies can present financial information in the required statutory format. The reports use existing Schedule III account tags, helping businesses prepare compliant financial statements more easily.
Original PR description
Add the Schedule III Balance Sheet and Profit and Loss reports based on the account classification defined by the Schedule III Chart of Accounts. These reports use the Schedule III account tags present the financial information according to the required format. task-2381149
Odoo now supports issuing Egyptian Tax Authority e-receipts directly from Point of Sale orders. This helps Egyptian retailers validate, submit, track, and reprint compliant electronic receipts as part of the normal checkout flow.
Original PR description
Introduce a new localization module integrating the Point of Sale with the Egyptian Tax Authority (ETA) e-invoicing service so that PoS orders can be issued as e-receipts: signing, submission, status tracking and the customer-facing QR/receipt printout are handled at validation time and replayed from the ticket screen when needed. The shared serialization helpers used to build the ETA document are extracted from `l10n_eg_edi_eta` into a reusable `tools/eta_serialize.py` so both invoice- and PoS-based flows produce the same canonical payload, and product templates expose the activity-code fields required by the e-receipt schema. task-3925833 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Adds a new My Subscription area that lets on-premise customers manage databases, subscriptions, IAP services, and related account actions from one place. It brings subscription-management features closer to the SaaS experience and makes common actions like upgrades, support, pricing, and database renaming easier to access.
Original PR description
Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Delivery teams can now print CMR transport documents directly from the Barcode app. This works for individual transfers and batch deliveries, reducing the need to switch between apps during warehouse operations.
Original PR description
This commit creates a `bridge` module between `stock_fleet` and `stock_barcode` to allow users to `Print CMR` reports directly from the Barcode app for both picking and batch delivery operations. Community PR: odoo/odoo#280200 TaskId-6413050
Enhancements to existing features
The stock traceability report now shows both where products came from and where they went, including finished products and customers, within the same report. Expanding report lines is faster and clearer, with better visual hierarchy and highlights for locations that still hold stock.
Original PR description
Expand towards end products and customers: Instead of moving downstream moving from one report to the next, we're adding a way to find all the 'children' lines of the select stock move line(s). This way we can stay in the same report and have a global view upstream and downstream from any point in the chain. Moreover, we're modifying the Unfold/Fold button to fetch all records in python before sending the final result at once to the JS. This limits the number of calls between JS and python to one. If we enter the report from the middle of a chain, there will be at least two lines show, one going upstream (parent line, existing behavior) and one going downstream (child line, new behavior). The most recent lines are shown at the top of the report. task 5265405 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Resolved issues and error corrections
Peruvian electronic invoices now include cash rounding in the final amount due sent to SUNAT. This prevents mismatches between the displayed rounding and the payable total in generated XML documents, reducing invoice validation or compliance issues.
Original PR description
Steps to reproduce ------------------ 1. On a peruvian company, set a cash rounding method on an invoice 2. Post the invoice and generate the SUNAT UBL 2.1 XML -> the rounding is in…
Steps to reproduce ------------------ 1. On a peruvian company, set a cash rounding method on an invoice 2. Post the invoice and generate the SUNAT UBL 2.1 XML -> the rounding is in `PayableRoundingAmount` but `PayableAmount` still has the amount before rounding! Why it's happening ------------------ The generic code computes `PayableAmount` from `amount_residual`, and Peru overrides it to be the total tax included of the XML minus the prepaid amounts, because the residual can not be used there. Then odoo/odoo@b847552872ad changed the meaning of the totals. The cash rounding line is not part of the base lines anymore, its amount is kept aside in `cash_rounding_base_amount_currency` and the totals do not contain it anymore. The generic code stays correct because `amount_residual` already has the rounding inside but the Peru total using `tax_inclusive_amount_currency` is now the amount before rounding and this is what ends up in the `PayableAmount`! The fix ------- Add the cash rounding amount when computing the `PayableAmount`. opw-6509677 Forward-Port-Of: odoo/enterprise#130732 Forward-Port-Of: odoo/enterprise#129983
Code cleanup and technical improvements
Time off accruals are now calculated more consistently, especially around carryover dates, plan level changes, and accruals granted at the start of a period. This helps employees and HR teams see more accurate leave balances, including future balances shown in the dashboard.
Original PR description
## Issues ### Accrual allocation initialization issue For an accrual allocation, due to `_add_lastcall` initialization method, the first carryover date could be skipped. Indeed this method only…
## Issues
### Accrual allocation initialization issue
For an accrual allocation, due to `_add_lastcall` initialization method, the first carryover date could be skipped. Indeed this method only includes the following accrual "events" in his `nextcall` computation:
- Carryover days expiration date
- Current level next period
- Next level transition
PS: The job of _add_lastcalls was to guess the value of nextcall, lastcall and actual_lastcall after saving the allocation
### Accrual allocation `_process_accrual_plans` issue
For an accrual allocation, to compute the number of days when the "accrued_gain_time" is "start", the code is using a bool field (already_accrued) and was trying to use the same logic as when "accrued_gain_time" is "end", but adding another alternative at the end of the loop. This was a bad idea as it has been proven that it leads to complex, hard to maintain, long, and bug prone code.
Here is the (impossible) challenge of this code:
The function `_process_accrual_plans` tries to update the `number_of_days` according to the accrual "events" (carryover, carryover expiring days, level transition, level period transition-daily-monthly-...). But the problem is that sometimes, it has to process multiple accrual events to compute the `number_of_days` of the allocation in the far future (possible when the user wants to see his number_of_days in the future from the time off dashboard). In this case, when the "accrued_gain_time" is "start" and using 'already_accrued', here's how the function works :
- Run through each accrual event until the nextcall is past the target date (same as when "accrued_gain_time" is "end")
- Run the additionnal alternative
This alternative set 'already_accrued' to True so that the next accrual event in the main loop doesn't accrue the days to the allocation.
But this code also has to take care of each day cron run. In that case, here's how it behaves:
- If the allocation nextcall happens before the target date:
- Run one iteration of the main loop, which probably doesn't add the accrued days as already_accrued is probably True.
- Run the additionnal alternative
This means that all the logic has to be at the same time in the main accrual event loop, and in the alternative, which is really hard, and led to the spaghetti we have today (which still contains a lot of bugs).
To avoid this issue, this PR separates the logic of each case ("accrued_gain_time" "start" or "end"), and removes 'already_accrued'.
## Accrual allocation `_process_accrual_plans` new feature
To make it easier to use, this method now returns a dict containing the accrual values of the allocations on the `target_date`, and do not directly apply the changes on the allocation anymore. For instance, this avoid having to create 'fake_allocation' using `new(origin=self)`.
However, it adds a little bit of complexity from the code, as some function now have to pay attention whether they should read the value from the values in the dict representing the data of the allocation, of the fields themselves (see class description for more explanations).
## Behavior correction
Before this PR, a day belonged to a level only if it was between the start of this level (not included), and the start on the following level (included). As the start of the level was not included, this could lead to some small issues like the days are only accrued on the second days of the level, even when "accrued_gain_time" of the accrual plan is "start".
## Tests
As I spend a lot of time making the tests work, I took this opportunity to make a few changes, mostly to make test simpler to understand, or to correct the tests that were doing wrong assertions.
## Accrual allocation refactoring
- Deleting the property "already_accrued"
- Renaming
- lastcall -> last_accrual : as described in the definition of lastcall, this property contains the "Date of the last accrual allocation"
- actual_lastcall -> lastcall : simpler name
- postpone_max_days -> max_carriedover_duration: clearer name, moreover, the unit of time of this field can be either 'Days' or 'Hours'
- expiring_carryover_days -> previous_carryover_number_of_days: the field expiring_carryover_days contains the number of days the allocation had on the last carryover, so this names fits best
- Adding a few fields to the Form: when creating an allocation with an accrual plan in a Form, everything was running smoothly, and the number_of_days was computed correctly. However, when saving the allocation, as the lastcall, actual_lastcall and nextcall were not saved (no fields matching them in the Form), they needed to be recomputed. So the method _add_lastcall was called to try to approximate what were the values of each of these fields depending on the fields.Date.today().
- Getting out of the infinite compute dependency of `number_of_days`, `number_of_days_display` and `number_of_hours_display`. Those fields were 3 computes fields depending on each other (and the orm was not made to use it that way) -> `number_of_days` is not computed anymore, and the 2 other fields set it using 'inverse' (more standard way of doing things).
task-5977748
[upgrade-8081](https://github.com/odoo/upgrade/pull/8081)Readonly image fields now hide the buttons for editing or clearing images. This prevents users from seeing actions they cannot use, making forms clearer and reducing confusion in kanban-based workflows.
Original PR description
Purpose ======= When the field is readonly, hide the "clear" and "edit" button for the `x2many_image_field` widget. Task-6323897
Accrual entries now include clearer labels so users can better understand and track what was generated. The process also detects possible duplicate accruals for the same period, reducing the risk of repeated accounting entries and cleanup work.
Original PR description
This commit improves the creation of accrual entries by: 1. adding context dependant strings allowing the user to easily track what kind of accrual entry has been created. 2. adding a mechanism to detect and handle duplicate accrual entries for the same period. task-6484921
The barcode tools now use a reusable view that combines camera scanning and manual barcode entry. This makes the scanning experience easier to expand and lets teams control whether the manual input field automatically receives focus.
Original PR description
Input focus is made conditional for the BarcodeInput component, to allow users to disable it if desired. It is enabled by default task-4170451 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
On-hand quantity links in stock reports now open the detailed stock quantities view directly. Lot quantities also reuse the existing filtered view, making it easier for users to inspect stock details consistently.
Original PR description
This commit's changes: - Redirect the stock report's on-hand quantity to the quant action. - Make the lot quantity call the existing lot-filtered quant action. task-6445662 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Website editors now have more control over product snippets, including grid or carousel layouts, column settings, and an option to show all products by website order. The settings have also been renamed and reorganized to make product presentation easier to configure.
Original PR description
**Post this commit:** - Added Orientation option for choosing Grid/Carousel layout. - Added an 'All' Filter to fetch products based on website sequence, rather than a specific rule. - Added Columns and Mobile columns to get more precision in terms of layout. - Renamed 'Show Variants' and 'Product Names'. - Reordered some of the settings. - Removed scrolling mode and making it single by default just for the product snippet. **Affected Version**-master Task-5167730 Docs PR: https://github.com/odoo/documentation/pull/16668
The command-line module tools now show which apps would be installed, upgraded, or removed before changes are applied. Users can also list installed apps and see pending updates, making database maintenance safer and easier to plan.
Original PR description
Show the modules that would be installed, upgraded or removed by running the command. Also allow listing installed modules. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Private calendar events are now counted when showing availability for appointments, while still hiding their details from people who should not see them. This helps prevent double-booking by showing users as busy even when the underlying event is private.
Original PR description
https://github.com/odoo/enterprise/pull/122675 When a user creates a private event, it shows up as 'Busy' with no additional details in the calendar module. This behavior was not mirrored in the…
https://github.com/odoo/enterprise/pull/122675 When a user creates a private event, it shows up as 'Busy' with no additional details in the calendar module. This behavior was not mirrored in the gantt view, meaning that we couldn't see the actual availability of the user. Additionally, if the user has their default calendar privacy set to private, any event created through the appointment view will automatically be private and hidden from all other (non-attending) users. Why? When we fetch events in calendar, we do a search and go through `_fetch_query` which censors non-public fields if the user doesn't have access to a private event. In the gantt view, however, we first do a `_read_group`. Since _read_group only returns ids and does not fetch fields directly, it filtered out the private events entirely. This is not entirely necessary, as whenever we want to read the events based on the retrieved ids, we still go through `_fetch_query` which censors them. Hiding the ids themselves is not needed, as they can be read using a search anyway. This commit therefore removed the `_read_group` event override. To make sure that the events are accounted for in the availability computation, we need to fetch them with sudo in `_get_busy_calendar_events` to bypass the censorship, as we need the partner_ids to create the interval mapping. The enterprise counterpart handles displaying the busy events in the gantt view. Task-6237805
Adds a new accounting setup for Indian companies that need to prepare financial statements under Schedule III. The existing Indian template is renamed for non-corporate entities, while corporate entities get the required account classifications and tags for compliant balance sheet and profit and loss reporting.
Original PR description
Schedule III provides the format and classification for the financial statements of companies required to prepare their financial statements accordingly. In this commit, rename the existing chart template to `Non-Corporate Entities` and add a new `Corporate Entities` chart template with the Chart of Accounts and account tags required for Schedule III. The account codes from the existing Chart of Accounts are also removed, as they are not prescribed by the Indian government and are not mandatory for any specific purpose. These will provide the required account classification and will be used by the Schedule III Balance Sheet and Profit and Loss reports. task-2381149
CRM lead cards now show the sales team when viewing leads across all sales teams, making it easier to understand ownership at a glance. Helper text was also adjusted so the wording stays clear whether the team switcher is active or not.
Original PR description
- Display the crm team on the lead kanban card when the switcher is activated and the "All Sales Teams" is selected. This improves the team visibility when leads from different teams are displayed. - Reword the helpers to make sure the wording works whether or not the team switcher is activated. Task-6537623 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Belgian payroll now includes the monthly employer ONSS reduction directly on payslips, instead of only calculating it in the quarterly DMFA report. This gives companies earlier visibility into expected social security costs while keeping quarterly totals aligned with official reporting.
Original PR description
Currently the ONSS deductions for the employer are only calculated in the DMFA report every quarter, but are not reported on the payslips, so companies do not have a clear idea of the ONSS contribution they will have to pay. This commit adds a salary rule to calculate the monthly reduction amount using the computation in the DMFA report. Since the DMFA contribution and deduction are quaterly calculations, the payslips for the whole quarter are required for accurate calculations. Since the DMFA report requires validated payslips to access line IDs, the remuneration processing was adapted to use the localdict for the current payslip. The ONSS reduction rule is processed towards the end of the computation so the required lines should be available. task-6108623
Social media managers can now set different scheduled times for each social channel within one post, making multi-channel campaigns easier to coordinate. The update also refreshes social calendar and card views, separates likes, comments, and shares for clearer reporting, and adds controls to cancel posts that are still being published.
Original PR description
Purpose ======= Allow specifying a schedule date per media, like we did for the message, images, first comment, etc. In the calendar view, we show the post from the smallest date to the latest date. When moving card in the calendar view, we try to keep the same hour of the day of all scheduled date share the same day (most of the time, we will schedule different hour of the day for different media, and changing the day from the calendar view is convenient). Now the CRON is triggered when adding the post in the queue instead of for every scheduled dates update. We cannot schedule a post not in draft state. Improve the kanban cart of the social.media Improve the kanban view of the `social.live.post` to make it look like the `social.stream.post`. Like we have for `social.stream.post`, use the number of likes, the numbers of comments and the number of shares instead of aggregating everything into "engagement". Task-6323897
When an employee leaves, Belgian payroll now automatically prepares the required departure documents at the right point in the payroll process. HR teams also get easier access to these documents from the employee profile, reducing missed paperwork and manual follow-up.
Original PR description
Context: Terminating an employee doesn't generate any document anymore. Termination payslip and holiday attest used to be generated in the end of collaboration wizard, but this was removed. This commit generate the termination documents (termination payslip, holiday attests, 13th month payslip, employment certificate): - As soon as the last monthly payslip for an employee is created within a payrun - Or when the last orphan payslip is validated for that employee A flag on the departure prevents regenerating them a second time when that payslip is later validated. It also add a dropdown to the employee profile when a departure is registered, regrouping all the termination documents that can be generated for that employee. The employment certificate can also now be generated anytime under the cog menu, before it was only possible to do it if the employee was on end of collaboration. task-6482307
The barcode app now uses a more consistent scanning and manual entry experience across its screens, reducing confusion for warehouse users. Barcode Lookup product creation is also available from every scanner view, with added support for expiry-date handling when relevant.
Original PR description
Before the barcode app had inconsistent barcode scanning flows, sometimes a dialog was opened, sometimes you had to click on the 'gear' icon to input the code manually. Now it has been unified to follow the same flow. Moreover, capability to create a new product with Barcode Lookup is added to all barcode scanners to provide consistency. task-4170451
Belgian payroll now supports tax and social contribution reductions for first hires in DMFA reporting. This helps businesses apply the correct employment incentives more reliably and avoid reporting issues, including a safeguard against crashes when configuration values are missing.
Original PR description
Implement reductions for first hires in belgium DMFA. Task-5476927
Users now receive a clear warning when trying to delete a worksheet template that is already used by worksheets. This helps prevent accidental deletion of related worksheets and reduces the risk of unintended data loss.
Original PR description
Deleting a worksheet template deletes all worksheets using it, which was not explicitly mentioned prior to this commit. Hence, we display a warning when the user wants to delete a worksheet template, if it is used anywhere preventing them to delete unintentionally all their worksheets. task-6417105
The accounting review menu has been reorganized so users can find asset, loan, purchase, and sales review items in more appropriate places. The change also improves how accrued order review workflows connect with the updated wizard, supporting a smoother finance review process.
Original PR description
This commit cleans up the review menu by moving items to their appropriate space, it also sets up the logic to properly interact with the improved `account.accrued.orders.wizard`. task-6484921
VoIP users can now choose separate audio outputs for incoming call ringtones and active call audio, making headset and speaker setups easier to manage. The in-call menu also keeps key settings available during calls, including device selection, Do Not Disturb, and access to phone numbers.
Original PR description
task-6533808
Frontdesk visitor records now allow only one host, matching the kiosk experience where visitors can select a single person to meet. This keeps front desk, SMS, and WhatsApp workflows consistent and reduces confusion from assigning multiple hosts in the back office.
Original PR description
Given that from the kiosk front end a visitor could select only 1 host at a time, It doesnt make sense to allow relating multiple hosts from the back end. This commit changes the `host_ids` field on `frontdesk.visitor` from a many2many field to a many2one field `host_id`. task-6514675
Appointment scheduling checks are reinforced so private calendar events are counted when determining whether someone is unavailable for a booking. This helps prevent appointments from being offered when a team member already has a private commitment.
Original PR description
Make sure that private events are correctly taken into account when computing the unavailable partners for bookings. Task-6237805
The timesheet KPI header now uses less width when the leaderboard is hidden. This improves the visual fit of the page with the updated Frost design and helps avoid an overly wide header.
Original PR description
In this commit, we reduce the width of the kpi header if the leaderboard is not displayed. Due to the new frost design, the header was too wide and did not render well. task-6530653
Stacked list columns now align like regular numeric columns when their leading value is a number or amount. This makes list views easier to scan and keeps totals and grouped values visually consistent.
Original PR description
Columns declared with the `column` tag stack several fields in a single cell, but were always left-aligned, unlike plain numeric field columns. Such a column now takes the alignment of its first sub-field, since that is the one heading the cell: header label, data cells and group/footer aggregates are right-aligned when that field is a float, an integer or a monetary. opw-6533733
The view switcher now animates the selected highlight smoothly between buttons instead of jumping instantly. This makes switching between views feel more polished and visually clear for users.
Original PR description
Switching view moved the highlight of the switcher from one button to another in one jump. Paint it once, on the group, as a single layer travelling from the button being left to the one being activated. Switching view rebuilds the whole control panel, so the switcher that has to run the move is created only once the button it comes from is gone. That index is put on the document for the time of the switch, and '@starting-style' turns it into the first position the indicator renders at, which leaves the move itself to a plain CSS transition. The indicator is laid out as one button of the group, so at rest it covers exactly the background '.btn' used to paint - which it now leaves to the group. The group carries '--btn-active-bg' for that, the buttons still inherit it, and dark mode keeps overriding the one value. Code made by Claude Supervised by RFR
Odoo’s AI capabilities are now delivered through the Odoo AI in-app purchase service, with model selection managed centrally by Odoo. This makes AI features easier to maintain, allows model upgrades without user-side changes, and supports switching models during an AI session.
Original PR description
The AI features of Odoo are now provided through a new "Odoo AI" IAP service. - Provider/model selection is now handled on the IAP server side. The LLM model used will depend on the feature for which it is used. It can now be updated more easily when new models are released or older models are deprecated. - A generic format for messages has been introduced. Since we don't know in advance which LLM model will be used, it is necessary to store them in a provider agnostic format (see `ai/utils/types.py` for a description). Thanks to this, it is now possible to switch models during a session. task-[6334145](https://www.odoo.com/odoo/project/19060/tasks/6334145)
VoIP call forms and completed call activity messages now present key information more clearly, including summaries, status, date, duration, transcripts, and feedback. This helps users review calls faster while keeping sensitive cost information limited to administrators.
Original PR description
see commit messages Task-6512169
The Belgian payroll module now provides clearer explanations for employment bonus A and B directly in the payslip line tooltip. This helps payroll users better understand how these bonus lines are presented without changing payroll calculations.
Original PR description
1 - The explanation of the employement bonus A and B is improved
1.1 - (it is in payslip line's tooltip, next to the salary rule)
task-6448501This update makes it easier for businesses with multiple companies or branches to move, buy, sell, and value goods across company boundaries. It improves warehouse resupply routes, sales and purchase delivery options, stock valuation for intercompany transfers, and reporting visibility for intercompany deliveries.
Original PR description
[WIP] --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The invoice batch sending wizard now opens much faster, reducing wait times for large batches from minutes to seconds. Users can also review sent invoice details more easily, and the electronic invoicing banner now appears only when relevant.
Original PR description
[IMP] account: Enhance Send Batch Wizard - Previously, the Send Batch Wizard could take too long to appear due to doing too much unnecessary work. Benchmark results for 4,000 moves improved from 2 minutes to 7 seconds. - Added a dropdown menu to view the details of the sent invoices. - Fixed "Partner requested electronic invoices reception" banner was incorrectly displayed for non-default PEPPOL countries. task-6275573
The Bangladesh localization updates its taxes and chart of accounts to align with Finance Act 2026 requirements. Businesses get clearer statutory tax categories, better account rollups for reporting, and updated company accounting defaults while obsolete tax reporting setup is removed.
Original PR description
This commit replaces the percentage-based tax structure and the flat chart of accounts with the ones required by the Finance Act 2026, and removes the outdated tax report. Before: the 16 tax…
This commit replaces the percentage-based tax structure and the flat chart of accounts with the ones required by the Finance Act 2026, and removes the outdated tax report. Before: the 16 tax templates were grouped by rate alone (`VAT at 2%`, `VAT at 4.5%`, ...), which says nothing about the law a tax is levied under. The chart had no hierarchy beyond `active=False` range accounts (`100100-100199`), so nothing rolled up and a section-wise Trial Balance was impossible. `tr_form` no longer matched the NBR reporting format. Now: taxes sit on the three statutory pillars, Value Added Tax (VAT and Supplementary Duty Act, 2012), Tax Deducted at Source (Withholding Tax Rules, 2026) and VAT Deducted at Source (VAT and Supplementary Duty Rules, 2016), with VDS and TDS flagged as withholding so they are held back until payment rather than deducted on the invoice. The chart is a real `parent_id` hierarchy, `1 Assets` -> `11 Current Assets` -> `111 Cash & Cash Equivalents` -> `111400 Bank Suspense Account`, so accounts roll up by section. `bank_account_code_prefix` moves to `1111` and `_get_account_parent_xmlid` nests the auto-created journal accounts under `111` instead of leaving them outside the tree. The company defaults follow the new chart: VAT 15% on sales and purchases, fiscal year ending 30 June, and the inventory, exchange difference, bank and deferred accounts. The obsolete tax report is dropped along with its fiscal positions, which mapped nothing once the rate-based taxes were gone. task-6219535 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Improves performance when opening point-of-sale registers for newly created companies in databases with very large accounting histories. The system now checks smaller company data first, avoiding slow scans of millions of accounting lines and making the experience much faster for users.
Original PR description
When you create a new company in a database that has a lot of existing account move lines and you attempt to open a PoS register from the list view, `_compute_company_has_template` checks…
When you create a new company in a database that has a lot of existing
account move lines and you attempt to open a PoS register from the list
view, `_compute_company_has_template` checks `_existing_accounting` for
the new company and wil run a sequential scan on the entire account_move_line
table followed by a nested loop as the query planner assumes AMLs company_ids
will be roughly evenly distributed.
This is not the case in a new company that has no/very few AMLs.
This is because the query ran is:
`SELECT COUNT(*) FROM
(SELECT FROM "account_move_line"
WHERE (
"account_move_line"."company_id" IN
(SELECT "res_company"."id" FROM
"res_company" WHERE
("res_company"."parent_path" LIKE '3/%')
))
LIMIT 1)`
and the values of company_id being searched for aren't known until the
subquery runs.
Running a query more like
`SELECT COUNT(*) FROM
account_move_line
WHERE company_id IN (%s)`
is much faster
Since res_company will always be a smaller table, we can do the inexpensive
search first and then pass in the values so Postgres can do a cheaper
search and return faster.
Benchmark time of `_existing_accounting`:
| Company 1 AML count | Company 2 AML count | Pre-fix | Post-fix | Multiplier |
|---|---|---|---|---|
| 10,000,000 | 0 | 700 Milliseconds | 500 Microseconds | 1,400x |
| 20,000,000 | 0 | 1.35 Seconds | 1 Millisecond | 1,350x |
| 20,000,000 | 20,000,000 | 2 Milliseconds |1.3 Milliseconds | 1.5x |
| 50,000,000 | 0 | 3.25 Seconds | 1 Millisecond | 3,250x |
| 100,000,000 | 0 | 5.3 Seconds | 1.3 Milliseconds | 4,075x |
Query Plan Before:
```
"Aggregate (cost=0.08..0.09 rows=1 width=8) (actual time=5573.001..5573.002 rows=1.00 loops=1)"
" Buffers: shared read=571435"
" -> Limit (cost=0.00..0.08 rows=1 width=0) (actual time=5572.995..5572.997 rows=0.00 loops=1)"
" Buffers: shared read=571435"
" -> Nested Loop (cost=0.00..https://github.com/odoo/odoo/commit/1571439c0c70c1f1dc3229421e696b97ce1678f8.33 rows=20000086 width=0) (actual time=5572.988..5572.989 rows=0.00 loops=1)"
" Join Filter: (account_move_line.company_id = res_company.id)"
" Buffers: shared read=571435"
" -> Seq Scan on account_move_line (cost=0.00..971432.72 rows=40000172 width=4) (actual time=0.432..1913.934 rows=40000000.00 loops=1)"
" Buffers: shared read=571431"
" -> Materialize (cost=0.00..4.03 rows=1 width=4) (actual time=0.000..0.000 rows=0.00 loops=40000000)"
" Storage: Memory Maximum Storage: 17kB"
" Buffers: shared read=4"
" -> Seq Scan on res_company (cost=0.00..4.03 rows=1 width=4) (actual time=0.785..0.785 rows=0.00 loops=1)"
" Filter: ((parent_path)::text ~~ '3/%'::text)"
" Rows Removed by Filter: 2"
" Buffers: shared read=4"
"Planning:"
" Buffers: shared hit=574 read=77"
"Planning Time: 15.323 ms"
"Execution Time: 5573.060 ms"
```
Query Plan After:
```
"Aggregate (cost=4.46..4.47 rows=1 width=8) (actual time=1.972..1.973 rows=1.00 loops=1)"
" Buffers: shared read=3"
" -> Limit (cost=0.44..4.46 rows=1 width=0) (actual time=1.967..1.968 rows=0.00 loops=1)"
" Buffers: shared read=3"
" -> Index Only Scan using account_move_line__company_id_index on account_move_line (cost=0.44..4.46 rows=1 width=0) (actual time=1.965..1.966 rows=0.00 loops=1)"
" Index Cond: (company_id = 3)"
" Heap Fetches: 0"
" Index Searches: 1"
" Buffers: shared read=3"
"Planning:"
" Buffers: shared hit=3"
"Planning Time: 0.219 ms"
"Execution Time: 1.998 ms"
```
opw-6513885
Forward-Port-Of: odoo/odoo#285096Point of sale receipts now always show the base amount for each tax group, matching the earlier receipt layout. This makes tax lines easier for customers and staff to understand, especially when several taxes use the same base amount.
Original PR description
Revert the receipt tax summary design back to the 19.0 format, ensuring that the base amount is always displayed for each tax group. Before this commit, when all tax groups shared the same tax base, the base amount was hidden, leading to a flat tax listing. Now, the template always renders the tax groups in the format: "Tax [Name] on [Base Amount] [Tax Amount]" task-id: 6296906 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283120 Forward-Port-Of: odoo/odoo#270749
Belgian payroll now treats employee versions as concurrent when their worker code and DIMONA category match, so payslips automatically include the right related versions. Payruns now select employees and create payslips for each relevant employee-version combination, reducing manual selection issues and duplicate warnings.
Original PR description
For Belgian payroll, employee versions are now considered concurrent if their DIMONA category and worker code match, instead of only contract dates. So that change the logic in the payslip for where…
For Belgian payroll, employee versions are now considered concurrent if their DIMONA category and worker code match, instead of only contract dates. So that change the logic in the payslip for where if you select specefic version, the payslip will also include the concurrent versions with the same worker code and DIMONA category. And if all the versions are concurrent in the payslip period, you will not have an option to select specific version and the payslip will automatically include all the concurrent versions. For Payrun: now selects employees instead of versions A payslip is generated for every employee-version combination within the payrun period If an employee has multiple versions in the payrun period, a payslip is created for each version The previous tests did not account for the newly added concurrency. In some tests, so that calculate all the concurrent versions in the same payslip and merging two versions into a single payslip hit the contract's wage limit. Since the total payment was capped regardless of the combined payslip amounts, those tests nothing now . To resolve this, I changed the version dates to ensure each version is tested separately. Additionally, I removed test_bik_first_payslip_unpaid. That specific scenario no longer exists now that the versions run concurrently. Task Id: 6126845
Appointment teams can now choose a specific email template to request customer feedback after a visit. This helps businesses collect service ratings in a controlled way, while leaving the setting empty by default to avoid unexpected emails for existing appointments.
Original PR description
Businesses often need to collect customer feedback after an appointment takes place to evaluate service quality and drive continuous improvement. Currently, Odoo only supports default templates for bookings and cancellations. This change links a specific mail template for post-visit feedback directly within the appointment type configuration. It is left empty by default to prevent breaking existing flows or sending unwanted emails during data migration. task-6268987
Belgian payroll now flags four additional issues before DMFA reporting, including mismatched location unit dates, incompatible remuneration codes, and payslips created before the company's first scheduled pay. These warnings help payroll teams catch compliance problems earlier and reduce the risk of incorrect social security declarations.
Original PR description
Adding 4 warnings on payroll dashboard and payslip model - Check if DMFA location unit cover the payslip date range - Check employers with code 317 don't have remuneration code 2 - Check that employers with 100% credit time don't have remuneration code 1 - Check that there is no payslips starting before company first scheduled pay Task: 6297320
The WhatsApp embedded signup onboarding is now included directly in the main WhatsApp module instead of a separate add-on. This simplifies maintenance and setup without changing the experience for existing users, since both parts were already installed together.
Original PR description
whatsapp_oauth is a separate module because the Embedded Signup onboarding had to ship in stable, where whatsapp itself cannot be touched. In master that constraint is gone, so it is folded back in. The module was auto installed and depended on whatsapp, so every database already had both. The code only moves, nothing changes for them. `WhatsAppOAuthApi` is folded into `WhatsAppApi` as well, which drops the `_api_requests` passthrough that only existed so a subclass could reach the name mangled request helper. The proxy endpoint parameter is renamed from `whatsapp_oauth.endpoint` to `whatsapp.proxy_endpoint`, it no longer names a module that exists. Task-6529850
Dutch SBR and ICP report submissions now go through Odoo's proxy service instead of connecting directly to Digipoort. This simplifies the submission process and lets businesses use either their own certificate or Odoo's shared group certificate.
Original PR description
*: l10n_nl_reports_sbr{,_icp,_status_info}
---
Description of the issue this commit addresses:
Dutch SBR and ICP reports still send directly to Digipoort with duplicated SOAP/signature code and no shared group-certificate flow.
---
Desired behavior after this commit is merged:
This commit routes both reports through IAP proxy signing/sending, and lets users submit with either a personal certificate or Odoo's group one.
---
IAP PR: https://github.com/odoo/iap-apps/pull/1593
Upgrade PR: https://github.com/odoo/upgrade/pull/11237
task-3439634
Forward-Port-Of: odoo/enterprise#117617Asset records now show the related bill lines more accurately when non-deductible taxes are involved. This prevents tax amounts from being hidden or incorrectly combined when several assets are created from the same vendor bill.
Original PR description
Previously, tax lines lacked a direct link to their parent base line, causing non-deductible taxes to be omitted from the asset's "Bills" tab and merged across multiple assets on the same bill. In this commit - `asset_base_line_id` is added to track the parent base line for asset generating accounts - overrides for `_prepare_base_line_tax_repartition_grouping_key` and `_prepare_tax_line_repartition_grouping_key` are added to force the tax engine to generate distinct tax lines per asset base line - `display_move_line_ids` is introduced to safely display both the base and tax lines in the "Bills" UI Task-6283724
Delivery operations can now include the Consignment Note (CMR) in their automatic print options when a delivery is validated. This also applies to point-of-sale deliveries, helping teams produce required transport paperwork with less manual effort.
Original PR description
Add the `Consignment Note (CMR)` report to the `Print on Validation` options for delivery-type operations, allowing users to automatically print the CMR report when validating a delivery. Apply the same behavior to POS deliveries. Enterprise PR: odoo/enterprise#128943 TaskId-6413050
The user interface icon library has been updated with additional icons for VoIP log types. This helps make VoIP activity logs clearer and easier to recognize in the application.
Original PR description
This commit adds new icons to the Material Symbols library to be used for log types in the voip module. task-5864994 Requires: - https://github.com/odoo/enterprise/pull/128919 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The point-of-sale hamburger menu now opens as a dialog instead of a dropdown, making buttons larger and easier to tap. This improves day-to-day usability on touchscreen devices across standard POS, employee POS, restaurant, and self-order flows.
Original PR description
*pos_hr, pos_restaurant, pos_self_order In this PR we've changed the layout of the hamburger menu buttons so they're more easily clickable on devices. We've switched the dropdown menu with a dialog. task-6253998 Enterprise https://github.com/odoo/enterprise/pull/118961 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Bank statements can now be created in draft and explicitly posted when ready, giving accounting teams more control before finalization. The update also protects journals that require secure sequencing by preventing incompatible draft statements or journal type changes once hashed statements exist.
Original PR description
- Add `is_statement_posted` field: Introduced to support a "draft" state when creating a statement directly from the form view. - Add Post/Draft Actions: Added `action_post` and `action_draft` for statements. Resetting to draft (`action_draft`) will also trigger move hashing if required. task-5170039 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The Italian electronic invoicing form now narrows the document type list based on the kind of accounting document being created. This makes it easier for users to choose the correct option quickly and reduces confusion during invoice entry.
Original PR description
In IT account move form view, add a filter on the document type field to display only possible document type for the move type. This should help users to find the right type faster and reduce confusion Task [link](https://www.odoo.com/odoo/project.task/6152691) task-6152691
Belgian payroll declarations are now tied directly to the payslips they report, making it easier to identify which payroll records need review when corrections are required. The reporting process also avoids reprocessing already reported payslips and uses a more reliable way to detect when corrections are needed.
Original PR description
- change the dmfa linking to be with its related payslips instead of employees which makes it easier in case of correction to track which payslips need checking - generalize dmfa correction to include web reports as well - only payslips that haven't been reported will be fetched instead of regenerating the report with all the month's payslips - the mechanism to detect the need of a correction is now more robust using a boolean that gets updated when a payslip is moved to done instead of the dates comparison previously used task-6326405
The point-of-sale hamburger menu buttons have been updated to match the newer modal layout. This creates a more consistent cashier experience across enterprise POS, IoT, and country-specific POS flows.
Original PR description
Following a change of layout for the hamburger menu buttons we've adapted these buttons to fit with the rest of the buttons in the modal. task-6253998 Community https://github.com/odoo/odoo/pull/267462
Payroll settings for Belgian localization now follow the company selected by the user. When switching companies from the payroll settings screen, users are redirected to the selected company’s settings list, reducing confusion and the risk of editing the wrong company’s configuration.
Original PR description
Currently, on Payroll config settings list and form view when we switch the company, We're still on the initially selected compan settings version. This behavior could lead to confusion and users have chance editing field that not belong to the company they switched. This PR expected If the user changes company while on the payroll setting version form or list view, they should be redirected to the newly selected company's setting version list view. How to access the view - Settings -> Payroll -> Configure (Belgian Localization section) task-6478413
This update refines the VoIP softphone experience with clearer icons, better button feedback, improved dropdown behavior, and more consistent spacing and alerts. These changes help users better understand call actions, settings, and activity context while reducing small visual issues that could cause confusion.
Original PR description
*: voip_hr_recruitment, voip_sale_subscription ### Update UI icons This PR updates several UI icons to improve consistency across actions and activity, while making them more relevant and easier to…
*: voip_hr_recruitment, voip_sale_subscription ### Update UI icons This PR updates several UI icons to improve consistency across actions and activity, while making them more relevant and easier to understand. ### Add active state to action buttons Prior to this PR, action buttons that opened dropdowns had no active state, which could lead to confusion as users might not know which button had opened the dropdown. This PR fixes the issue by adding a proper active state whenever a dropdown is open. ### Adapt top info message layout in softphone This PR revises the layout of the info message displayed at the top of the softphone to make it more consistent with other info alerts. ### Show correctly softphone navbar border Prior to this PR, the top border of the softphone navbar could disappear when scrolling. This PR ensures that the navbar border remains visible at all times. ### Review user settings dropdown items Prior to this PR, the "Do not disturb" dropdown items used custom utility classes that broke the hover state. This PR ensures that the dropdown correctly uses the standard dropdown item component. ### Add tooltip to many2one_reference_icon_field This PR adds a tooltip displaying the activity's "display_name" when hovering the `many2one_reference_icon_field` icon, helping users understand what the icon represents. ### Update o-voip-InCallView-pad spacing The current spacing in `o-voip-InCallView-pad` was initially designed to accommodate two additional action buttons that have not yet been implemented. For now, this creates an inconsistent spacing that can give the impression of a bug. This PR updates the spacing to better align with the action buttons currently available. task-5864994 --- 💡 _Preview screenshots are available in the task pad._ --- Requires: - https://github.com/odoo/odoo/pull/285621
Belgian payroll now includes certain unpaid but legally assimilated absences when calculating holiday pay tax provisions. When an employee leaves, the accrued yearly provision is cleared on the final payslip, improving payroll accuracy and preventing unreleased balances.
Original PR description
Before this commit, the holiday pay tax provision kept accruing every month but was never released, and it ignored the time off that is assimilated for the double holiday pay when it was not paid on the payslip. After this commit, the monthly provision base also covers assimilated but unpaid days (legal leave, public holidays, sickness, strike) so it keeps growing on those absences. On the employee last payslip the whole provision accrued during the year is emptied in a single negative line. taskid-6416109
Shop Floor users can now edit existing work instructions without starting from a blank editor, making small updates faster and less error-prone. The document viewer also works correctly for attached instructions, and newly captured pictures are added consistently to the instruction text without replacing worksheet documents.
Original PR description
[IMP] mrp_workorder: pre-fill the instruction when updating a step In the Shop Floor, "Update Instructions" opened the editor empty. A user making a small adjustment had to retype the whole…
[IMP] mrp_workorder: pre-fill the instruction when updating a step
In the Shop Floor, "Update Instructions" opened the editor empty.
A user making a small adjustment had to retype the whole instruction
again from scratch, without seeing what they were replacing.
The wizard is now pre-filled with the step's current instruction.
task-6459280
---
[FIX] mrp_workorder: fix the document viewer on Shop Floor
Opening the instructions of a step holding a document raised
"this.props.value.startsWith is not a function" and left the dialog empty.
Since https://github.com/odoo/odoo/commit/23a7d8cc5b1d2f38eaee35a4f6729fe128c1b62b , reading a
binary field over rpc no longer returns a base64 string but a dictionary
holding its content, name and size.
Adapt to read the content out of that dictionary.
---
[IMP] mrp_workorder{,_plm}: append new picture to the instruction
"Set a New Picture" wrote the picture to worksheet_document, the step's
document attachment, and stripped the inline images out of the note.
But that field is presented as a PDF worksheet everywhere else.
mrp_workorder_plm did the opposite on the ECO's BoM step: it added the
picture to the note and cleared the attachment. The same action led to
inconsistent results.
The picture is now appended at the end of the instruction, on the work
order step and on the ECO, and the worksheet_document is left untouched.
task-6459280Payroll-related fields on time types are now updated automatically when payroll data changes. This keeps absence and work-entry configurations consistent across multiple local payroll packages, reducing manual upkeep and payroll setup errors.
Original PR description
…roll data update Task: 6410286
Bank statement handling is improved so users can choose relevant reconciliation models directly during the reconciliation and posting flow. This makes cash and bank journal processing more guided, while ensuring required hashing and reconciliation steps happen at the right time.
Original PR description
[IMP] account_accountant: improve statement flow and reconciliation models This commit improves the bank statement lifecycle, reconciliation model selection, and journal hashing behavior: -Allow…
[IMP] account_accountant: improve statement flow and reconciliation models This commit improves the bank statement lifecycle, reconciliation model selection, and journal hashing behavior: -Allow selecting from the top 5 reconciliation models (prioritizing journal-specific models, then falling back to global ones) directly in the bank reconciliation widget. Selecting a model triggers it on creation. - Hashing: If a statement is created in a hashed journal, force the reconciliation of the remaining unreconciled entries and hash the moves. - Statements accessed from the base view now start in "draft" state (including their lines). Users can select a reconciliation model to apply upon posting. Hashing is also deferred to the posting step. - Adjust the `from_bank_reco` context key to ensure it is passed correctly, resolving an issue introduced by the removal of `onWillRender` task-5170039 [IMP] l10n_be_reports: Adding reco models for cash journals When creating a cash journal, we will first create new reco models. If the reco models already exist then we will just add the new journal to the match_journal_ids. task-5170039
Belgian payroll now requires companies to provide insurance details when they have employees and holiday pay fund details when they have workers. This helps ensure payslips and individual accounts include legally required information and warns businesses when required payroll company data is missing.
Original PR description
Purpose: Comply with Belgian regulation regarding holiday pay fund and insurance information that must be present on payslips and individual accounts. Implementation: - Insurance information is mandatory as soon as there are employees. Hence, enforced on the frontend. - Holiday pay fund is mandatory only when there are workers (see is_worker()). Hence, enforced on the frontend. - Modify existing warning for payroll company data to also track holiday pay fund & insurance fields. task: 6512348
Belgian payroll declarations now calculate research and development time more accurately across additional payslip types, including double holiday pay, 13th month, and termination payments. This helps ensure payroll reporting reflects the correct eligible R&D percentage for each employee period.
Original PR description
now we support more payslip structures in 274.XX ex: (DHP, 13Months, termination) we need to compute rd_percentage correctly this commit adds a method to compute the correct value, based on related employee versions. Task#6394245
Belgian payroll now rounds train travel distances down to the nearest available reimbursement bracket. This helps ensure reimbursements remain favorable to employees when exact travel brackets are not present in the train table.
Original PR description
In order to keep the train reimbursement in favor of the employees, all the train travel brackets have been floored to the nearest threshold available in the train table. Task: 6485650
VoIP administrators can now submit a request when no suitable phone numbers are immediately available. The system tracks these advanced orders over time and automatically creates or assigns the number once the provider fulfills the request, reducing manual follow-up and improving number availability.
Original PR description
```mermaid
sequenceDiagram
actor Admin
participant E as Enterprise VoIP
participant I as IAP Phone Service
participant T as Telnyx
Admin->>E: Search available numbers
E->>I: Search request
I->>T: Search inventory
T-->>Admin: No numbers
Admin->>E: Ask us / Submit Request
E->>I: Create advanced order + request UUID
I->>T: POST /advanced_orders
I-->>E: Accepted, no charge
Note over I,T: May remain pending for days
T-->>I: advanced_order.status_update = ordered
I->>T: Read generated standard Number Orders
I->>T: Fetch current monthly price
I->>I: Adopt standard orders + reserve billing
I->>T: Resolve/configure actual phone resources
I-->>E: Signed normal phone-number status events
E->>E: Create/reuse DID and assign requester
```
[Task-6529404](https://www.odoo.com/odoo/project.task/6529404)
IAP: https://github.com/odoo/iap-apps/pull/1842Self-order table sessions now pass the right order identifier through the preparation display flow. This helps keep QR-code-based table orders linked to the correct session, supporting a smoother restaurant ordering experience.
Original PR description
Add order_uuid parameters into pos_self_order_preparation_display controllers task-4934385 see https://github.com/odoo/odoo/pull/222152
Restaurants can now create a one-time QR code when seating guests, print it on a ticket, and let customers use it to access the self-ordering menu for that visit. The code is invalidated after payment, reducing reuse risk and supporting more controlled table-based self-ordering workflows.
Original PR description
To support common self-ordering workflows, restaurants require dynamic, single-use QR codes generated per visit rather than static QR codes per table. Specification: - Allow staff to generate a dynamic QR code when seating a customer in the POS. - Extend POS receipt functionality to print the dynamic QR code on a physical ticket. - Enable customers to scan the ticket to access the self-ordering menu for their session. - Add validation to ensure the QR code is immediately invalidated and cannot be reused once the payment is validated. task-4934385
Entering a VAT or GST number in the partner name field now correctly triggers partner autocomplete again. This helps users find and select existing partners faster, reducing manual entry and duplicate records.
Original PR description
PURPOSE - Typing a VAT/GST number in the partner name field failed to trigger the autocomplete. - This was due to a [refactoring](https://github.com/odoo/odoo/pull/272884/changes#diff-0a5505b3e2038534267e3af27e91e6466d9326d8954d38c4bc44d69fa333989eR68) that restricted VAT validation strictly to the `vat` field. SPECIFICATION - We are automatically switching the search logic to VAT if a valid VAT/GST number is detected inside the name field. task-6544712
This fixes a timing issue in the restaurant point-of-sale order tracking test by waiting until order validation and syncing are complete. It helps prevent false test failures where the system checked order details before the latest changes reached the backend.
Original PR description
The order tracking tour only waited for the feedback screen to be shown after validating the payment. Since order validation is performed asynchronously while the feedback screen is displayed, the tour could finish before the updated order was synced to the backend. This caused the Python test to still see the original quantity and `is_edited` set to false. To fix we wait for the feedback screen continue button to be enabled, which ensures order validation and synchronization have completed before the tour ends. [error-940386](https://runbot.odoo.com/odoo/error/940386) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282726
Customers who open an order through a secure access link can now use the Return button without signing in. This fixes a broken self-service return flow and reduces friction for portal or guest customers returning delivered items.
Original PR description
Accessing an order on the website without connecting (only with the access token) doesn't allow the user to return the order (nothing happens when click on the "Return" button) Steps to reproduce: 1.…
Accessing an order on the website without connecting (only with the access token) doesn't allow the user to return the order (nothing happens when click on the "Return" button) Steps to reproduce: 1. Install Sales and Inventory 2. Go to Settings > Inventory > Operations and enable "Allow Spontaneous Returns" 3. Go to Sales and create a new quotation for customer "Acme Corporation" with product "Acoustic Bloc Screens" and confirm it 4. Go to the related delivery, set the quantity to 1 and validate it 5. Go back to the sale order and click the "Preview" smart button 6. Copy the url (/my/orders/<id>?access_token=...) and open it in an incognito window 7. Click the return button on the order page 8. Nothing happens Issue: The route to `my_order_return_data` requires the user to be logged in Solution: Make the routes `my_order_return_data` and `order_return_label` public For 19.4: access `return.reason` records with sudo (should be removed in master) For master: add read right on `return.reason` for all users opw-6487767 Forward-Port-Of: odoo/odoo#285290
This fix removes leftover setup data from an earlier change that could conflict with current repair subcontracting records. It helps keep the manufacturing repair configuration consistent and avoids unexpected conflicts during use or upgrades.
Original PR description
An old refactor left some data around that are in conflict with other records for the same model. Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282103 Forward-Port-Of: odoo/odoo#281276
Manufacturing order notes in the shop floor view now stack vertically instead of appearing as separate columns. Long notes are contained in a small scrollable area, keeping the layout consistent and easier for operators to read.
Original PR description
Before : As multiple notes on MO are stored as a conjunction of div, they are shown as multiple columns in the shop floor view due to the flex layout. After : Wrap the notes in a scrollable container capped at 3 lines so the line height stays consistent regardless of note length. Changes: As we want to keep the edit icon aligned as it is, we keep the flex layout and wrap the notes in a separate div with a vertical flex container. We furthermore limit the height of the note to 3 lines with an overflow auto so that the line height stays consistent regardless of note length. [opw-6544909](https://www.odoo.com/odoo/project/966/tasks/6544909)
This fix prevents errors when company car benefit values are calculated outside Belgian company contexts or when expected payroll parameters are missing. It improves reliability for multi-company setups and avoids interruptions for users managing vehicle models across different countries.
Original PR description
. Handle multi-company and non-Belgian contexts in fleet.vehicle.model's . Add raise_if_not_found=False when retrieving min_car_atn to prevent UserError/TypeError when parameter records are missing or when processing non-BE models. . Add test to verify that computing BIK for non-Belgian companies executes safely without exceptions. task-6544760
Customers can now open signed report PDFs from the portal history without the preview crashing. This ensures Field Service reports remain accessible after signing while preserving the existing backend signing workflow.
Original PR description
Steps to reproduce: - Open a Field Service shift that has a customer (in progress or done). - Click Sign Report, sign, and confirm. - In History, click the report PDF. Before this commit: the preview crashed instead of opening. After this commit: the PDF opens on the portal. In the backend, the Sign button in the viewer still opens the template editor. The viewer Sign button needs the backend action manager, which does not exist on the portal. Requiring it blocked the preview itself. task-6535111
The Field Service planning Gantt view now opens without waiting for buffer time calculations to finish. This reduces potential delays for users, while the missing timing details are filled in automatically as soon as they are ready.
Original PR description
This commit fixes a potential performance issue in the Gantt view of Field Service when computing the buffer times. Prior to this commit, the view waited for the buffer times to be computed before rendering. With this commit, we trigger the buffer time computation in the background (i.e., fire and forget), while letting the view to render. As buffer times are computed, the view will be notified. no-task Forward-Port-Of: odoo/enterprise#130782
This fixes automated Point of Sale stock test scenarios so they can find the intended test customer even when many demo customers are present. It helps keep test runs stable and prevents false failures during quality checks.
Original PR description
When running tests with demo data, the partner list is populated with many records, causing 'Partner Test 1' to fall outside the initial 100 loaded partners in the PoS session cache. Because clickCustomer defaulted to pressEnter=false, searching in the UI filtered the in-memory cache and displayed 'No customers found, press Enter to load more.', but never dispatched the Enter key to fetch the partner from the backend, timing out the tour step. Pass pressEnter=true in pos_stock customer selection tours so that the Enter key is dispatched and the partner is fetched from the server via RPC. runbot-error: 242001 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286513
Fixes the French association balance sheet so active and passive totals include the right lines and avoid double-counting entries. This helps associations relying on Odoo financial reports see accurate balance sheet totals for compliance and decision-making.
Original PR description
## [FIX] l10n_fr_reports: fix missing lines in association balance sheet ### Issue: The Active part of the Balance Sheet for associations shows an incorrect `TOTAL ACTIVE` — some accounts are not…
## [FIX] l10n_fr_reports: fix missing lines in association balance sheet ### Issue: The Active part of the Balance Sheet for associations shows an incorrect `TOTAL ACTIVE` — some accounts are not propagated to their parent aggregations ### Cause: `ACTIF_IMMOBILISE` was missing `BIEN_PAR_DONATION` in its formula `ACTIF_CIRCULANT` was missing both `DISPONIBILITES` and `INSTRU_FINAN` in its formula ### Steps to reproduce: - Install `l10n_fr_reports` and `accountant` - Create a new FR asso company and switch to it - In Accounting Settings, select: France - Associations accounting plan - Create a Journal Entry: Account: 240000, Debit: 100 (BIEN_PAR_DONATION) Account: 512001, Debit: 100 (DISPONIBILITES) Account: 520000, Debit: 100 (INSTRU_FINAN) Account: 509000, Credit: 300 - Open the Balance Sheet and select Balance Sheet for associations Before the fix, `TOTAL ACTIVE` is 0 instead of 300 -------------- ## [FIX] l10n_fr_reports: add force_date_scope to asso cross_report ### Issue: The Passive part of the Balance Sheet for associations shows an incorrect `TOTAL PASSIVE` — the same move line is counted twice, once in `Retained earnings` and once in `Profit or loss for the year` ### Cause: In 19.1, `cross_report` aggregations were refactored: https://github.com/odoo/enterprise/commit/e699a14a1922d6b8a5bc6b88ad9c02a411e4b073 By default, a `cross_report` no longer forces its `date_scope` to the terms it calls — `force_date_scope` must now be explicitly passed in the subformula The association balance sheet was added in 19.1 without this parameter, so `RESULT_LEXERCICE` (`from_fiscalyear`) and `REPORT_NOUVEAU` (`to_beginning_of_fiscalyear`) both used the current report's `date_scope` instead of their own This caused both expressions to match the same entries and double the `TOTAL PASSIVE` ### Steps to reproduce: - Install `l10n_fr_reports` and `accountant` - Create a new FR asso company and switch to it - In Accounting Settings, select: France - Associations accounting plan - Create a Journal Entry: Account: 512001, Debit: 100 Account: 701100, Credit: 100 - Open the Balance Sheet and select Balance Sheet for associations Before the fix, `TOTAL PASSIVE` is 200 instead of 100 opw-6520639 Forward-Port-Of: odoo/enterprise#130147
Users with permission to edit a spreadsheet can still rename it after refreshing the page. This fixes a problem where refreshed spreadsheet links were incorrectly treated as read-only, reducing confusion and preserving normal editing workflows.
Original PR description
Spreadsheet backend URLs now contain an access token for regular users. After a refresh, the router restores this token and the navbar treated its presence as read-only, even when the user had write access. An access token identifies the spreadsheet URL and collaborative session; it no longer indicates that the current user is read-only. Actual permissions are provided by `has_write_access`, while archived spreadsheets are handled by `spreadsheetMode`. Use the spreadsheet mode as the single source of truth for both spreadsheet content and filename edition. Task: 6496749
This fix changes the registration flow so Odoo checks for an existing proxy user before contacting the external IAP service. It prevents rare concurrent registrations from leaving a database with outdated credentials that block later electronic document proxy calls.
Original PR description
In the current flow, _register_proxy_user first calls IAP create_user, then inserts the returned credentials in account_edi_proxy_client.user. At the same time, IAP create_user_2 may replace an existing user with a new one with different credentials before local persistence settles. So Tx A calls IAP and gets credentials for remote user U1. Tx B calls IAP and gets credentials for remote user U2 and unlinks U1. Tx A persists U1 locally. Tx B fails local insert due to a unique constraint. Client DB keeps U1 credentials, but IAP now expects U2. Subsequent proxy calls from the client fail. The DB is left with stale, unusable credentials and cannot recover without re-registration. IAP: https://github.com/odoo/iap-apps/pull/1816 task-6520501 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285648
The accounting module now uses today's date when a required reporting date is not provided. This prevents an unexpected error from interrupting currency consolidation calculations and keeps accounting workflows running smoothly.
Original PR description
`date_to` is accessed directly from `self.env.context` in `_compute_sql_consolidation_rate`. When the key is missing from the context, this raises an error and breaks the flow. Use today's date as the default value when `date_to` is not provided in the context, preventing the traceback and allowing the computation to continue normally. Forward-Port-Of: odoo/odoo#286965
Changing a shift will no longer automatically restore a sales order line that a user intentionally removed. The sales link is now updated only when the related project or task changes, helping keep staffing and billing information aligned with user intent.
Original PR description
Before this commit, when a change is made in a shift, the SOL initially removed by the user can be set by the one set on the task/project linked to that shift. The reason is because each time the compute of SOL field is triggered, the compute will set the SOL of the task or the project linked. The problem is we only want that behavior when the user changes the project or the task. This commit removes the logic the compute to set the SOL of the project/task, to do that logic inside an onchange method instead. Task-6354078 Forward-Port-Of: odoo/enterprise#130739 Forward-Port-Of: odoo/enterprise#125814
This fix makes Odoo's mail tracking tests use a consistent language setting instead of depending on each developer or server machine's regional settings. It prevents false test failures in accounting, CRM, HR recruitment, manufacturing, mailing, and related modules when systems are configured in non-US English locales.
Original PR description
Since the removal of tracking values, they are only accessible formatted and localized embedded into mail messages. This means when we try to check them in tests, we need to format the "reference"…
Since the removal of tracking values, they are only accessible formatted and localized embedded into mail messages. This means when we try to check them in tests, we need to format the "reference" values using the same locale. During testing the locale is *generally* `en_US` because that's the default for odoo / test users, but `TransactionCase.env` does not have a lang configured at all, so when tracking we call something like `babel_locale_parse(self.env.lang)` = `babel_locale_parse(None)`. `None` is obviously not a valid locale, so `babel_locale_parser` ~~raises an error~~ falls back, and the first fallback is `Locale.default()`, which checks the language / regional envvars (`LANGUAGE`, `LC_LANG`, `LC_ALL`, `LANG`) and returns the first valid one, otherwise `babel_locale_parse` then defaults to `en_US`. The middle case is the problem here, if a machine is configured with a locale other than `en_US` then that's what's used to format the tracking values against the stored message, so if someone's locale is `zh_TW` they get `2020年1月1日`, which for some reason does not match a english-US format, making pretty much every test checking tracking values fail. But hey for once it's not a babel version issue.
This update ensures the partner autocomplete identifier field is added through the correct module instead of being embedded in the core contact views. It also restores save and cancel prompts when users manually edit multiple identifiers, preventing changes from being missed.
Original PR description
This commit fixes 2 things : 1. the `additional_identifiers_list_partner_autocomplete` widget was hardcoded directly into the core `base` module's views for res.partner and res.company. 2. Manually editing the multi-ids field wouldn't show the save/cancel buttons. Fix af3f8f6bc267eb431c0be108f30c061f0b0e1c01 no task
This fix makes automated checks use a consistent language when verifying change history values. It helps prevent false test failures caused by translations, improving release reliability without changing customer-facing functionality.
Spreadsheet editing screens now consistently use a topbar color that blends with the main navigation, not just in the Documents area. This creates a more consistent and polished experience for users working with spreadsheets across the system.
Original PR description
The recent fix in #130001 to blend the topbar color with the navbar only worked for the documents action. This revision extends the behaviour for every spreadsheet editing action. task-6529910
The VoIP flow editor now keeps its visual layout consistent when used in right-to-left languages. This prevents misplaced connection points, resize controls, and overlapping text, making call flow editing more reliable for affected users.
Original PR description
The flow editor stores and computes its geometry using physical coordinates: inputs are placed on the left, outputs on the right, and nodes are resized from the bottom-right corner. RTLCSS mirrored some of the corresponding styles in RTL languages. This made ports and their labels inconsistent with SVG connections, changed the resize handle position and cursor, and altered the canvas transform origin. Prevent RTLCSS from flipping these geometry-dependent declarations so the editor behaves consistently in LTR and RTL. The record description in a terminal node's body was also missing min-width: 0 on its flex item, so text-truncate never actually constrained it: in RTL the text starts flush against the physically right-anchored output port labels, overlapping them.
Products added to an active Point of Sale session after it starts now receive the correct pricelist discounts or prices based on their category. This prevents unexpected full-price charges when staff add newly created products from categories covered by pricing rules.
Original PR description
Steps to reproduce: - Create a pricelist with a rule applied on a product category and make it available in the PoS - Open a PoS session - From the backend, create a product in a new category covered…
Steps to reproduce: - Create a pricelist with a rule applied on a product category and make it available in the PoS - Open a PoS session - From the backend, create a product in a new category covered by such a rule - Back in the PoS, find that product through Search > Search more and add it to the order Issue: The product is priced at its sale price, the pricelist rule set on its category is ignored. Cause: A product that is not part of the initial payload is loaded on the fly by load_product_from_pos, which sends back the rules returned by get_pos_ui_product_pricelist_item_by_product. That domain only matches the rules set on the template or on the variant, never the ones set on a product category, and the payload carries no product.category record either. The client therefore has neither the rule nor the category: parentCategories walks categ_id, which resolves to nothing, so getCategoryRulesIds returns no rule and getPrice falls back to the sale price. This stayed unnoticed because product.category is fully loaded when the session starts, along with every category rule, so only the categories created after the session was opened are missing. Fix: Send the categories of the loaded products, since a rule set on a parent category applies to its children - along with the products, and match the rules set on those categories in get_pos_ui_product_pricelist_item_by_product. The initial loading domain of product.pricelist.item no longer filters the category rules on the loaded categories: such a rule has to be loaded whatever the products sent to the client are, since a product of that category may be loaded later on. opw-6477745 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285721 Forward-Port-Of: odoo/odoo#284660
This fix stops Point of Sale invoice settlements in Argentina from incorrectly creating a separate zero-value invoice. It prevents settlement validation errors, allowing businesses to record customer payments reliably without consuming unnecessary electronic invoice numbers.
Original PR description
Steps to reproduce: - Argentinean company, Responsable Inscripto (l10n_ar_pos installed) - A posted customer invoice with VAT, partially paid - In the PoS, pick the customer, "Settle invoices",…
Steps to reproduce: - Argentinean company, Responsable Inscripto (l10n_ar_pos installed) - A posted customer invoice with VAT, partially paid - In the PoS, pick the customer, "Settle invoices", select that invoice, pay the balance by bank transfer and validate Issue: Validation fails with "There should be a single tax from the "VAT" tax group per line, but this is not the case for line ..." and the settlement cannot be recorded at all. The invoice being settled is correct; the rejected line belongs to a second invoice the PoS creates for the settlement itself. Cause: `setToInvoice` already refuses to invoice a settlement, but its condition, `is_settling_account and no line`, only describes a deposit: the deposit line is added at validation. When settling a due or an invoice, `is_settling_account` stays false and the order does carry lines - the settle lines - so the guard never fires. l10n_ar_pos then sets `to_invoice` on mount, as a sale must generate an electronic document in AR, and the settle line, untaxed on purpose since it pays an existing document rather than selling anything, reaches `_check_argentinean_invoice_taxes`. Fix: Refuse the flag as well when every line is a settle line. Such an order generates an empty document - all its lines, the receivable one included, have a zero balance - so it records nothing and only consumes a document number, which in AR means an AFIP number for a zero-amount invoice. An order that also sells something keeps its invoice, since the sale still has to be reported. Reconciliation is unaffected: it happens in `_reconcile_account_move_lines` at session close, and is already covered for both invoiced and non-invoiced settlement orders. opw-6464675 Forward-Port-Of: odoo/enterprise#129902 Forward-Port-Of: odoo/enterprise#128975
Odoo now ensures that a private chat between the same two people can only exist once, even when requests happen at the same time. This avoids duplicate conversations, preserves chat history when a contact is deleted, and keeps chat names clearer for users.
Original PR description
A chat between 2 persons should be unique, but it can currently be created multiple times because we don't have a proper constraint. A lock could be added in the main create route, but it wouldn't…
A chat between 2 persons should be unique, but it can currently be created multiple times because we don't have a proper constraint. A lock could be added in the main create route, but it wouldn't catch all flows, and it would also slow down the route and potentially create unnecessary retries. The best way to ensure uniqueness is to add a proper SQL constraint. As the combination of members depends on a x2many relational field, a new field is added to track this combination on the channel table. This is a similar pattern as combination_indices on product.product. The new field is computed during create and not with a compute: - compute are computed after creating the record in database, which makes it impossible to have SQL constraints to ensure the field is properly set, as it would initially not be set - chat with a partner that later gets deleted should be kept for history, in this case the member is deleted but the channel remains, re-computing the member_indices could lead to several channels with only the current user in it, which the constraint does not allow. This also significantly simplifies the search of existing chat channels. task-4664353 https://github.com/odoo/upgrade/pull/9120
This fix prevents electronic invoice imports from failing when an invoice line has a 100% discount together with tax included in the price. Odoo now recalculates the tax from the original price in this edge case, improving reliability for accounting document imports.
Original PR description
Due to the following commit: 01efd8cfcce3269ca6b88d549a670b08a90298cb, a division by zero error is raised when a 100% discount is used with a price-included tax. When the discount is 100%, it is impossible to retrieve the original tax amount before discount using a simple multiplication as the current raw_tax_amount_currency is zero. In that case, we need to recompute taxes using the original unit price before discount. opw-6242701 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283877 Forward-Port-Of: odoo/odoo#282430
Restored or duplicated databases using the neutralize option are now neutralized before the system makes them active for scheduled background work. This prevents automated actions from briefly running on a copied database before it has been safely disabled, reducing the risk of unintended emails, integrations, or jobs.
Original PR description
Before this commit: If you restore a backup or duplicate a database via /web/database/manager with "Neutralize" enabled, the cron workers had a small window between the creation of the Registry and the neutralization of the database where they could try to execute crons. Since neutralize_database does not require a full registry to run (it only does raw SQL operations), we can run it before the Registry creation (which has the effect, among other things, of making the cron workers aware of the new database). opw-6517819 Forward-Port-Of: odoo/odoo#286870 Forward-Port-Of: odoo/odoo#286532
Badge counters in the Discuss app now display correctly when they contain two or more digits. This prevents numbers from being cut off in tabs and messaging menu items, making unread or important counts easier to read.
Original PR description
This PR fixes the position of badge counter in tab and messaging menu item when they have more than 1 digits. Before / After <img width="401" height="466" alt="Screenshot 2026-09-07 at 23 41 58" src="https://github.com/user-attachments/assets/30d3a826-0898-4b5a-81a1-1ed816ed166b" /> <img width="403" height="466" alt="Screenshot 2026-09-07 at 23 34 36" src="https://github.com/user-attachments/assets/45687a6e-924d-413b-bd15-1b16bf5b012c" />
This fix prevents errors when sales reports or tracking references encounter outdated internal model records. It helps keep sales and marketing tracking features stable even when system metadata is temporarily out of sync.
Original PR description
Following 6dedae804748, in case `ir.model` models are out-of-sync with the available models in the registry, trying to compute the target selection model will result in a crash (`KeyError`). This commit ensure the target model is available in the registry to avoid that crash. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284541 Forward-Port-Of: odoo/odoo#284161
The Bangladesh reports module no longer includes an outdated tax return setup that depended on a removed report. This prevents installation failures while keeping the corporate tax report working through existing account tags.
Original PR description
This commit removes the tax return type built on the Bangladesh tax report, which no longer exists. Before: `bd_tax_return_type` resolved `l10n_bd.tr_form` through a `ref`. That report did not match the NBR reporting format and is dropped from the community module, so the reference would fail to resolve and take the whole module down with it at install. Now: the return type and the data file holding it are gone. The corporate tax report is untouched; it reads through the `account_tags_tax_c_exempt`, `c_cog` and `c_exp` account tags rather than through `tr_form`, and those tags are kept on the accounts in the community module. task-6219535
AI image generation and editing now receives the product or website image context that was previously being dropped when opening the media dialog. This prevents the AI assistant from asking for information it should already know and helps it generate results based on the correct product image.
Original PR description
When opening the media dialog from a product image (avatar) edit button, the `ImageFieldWithMediaDialog` (patched by the `ai`) attempts to pass `record`, `originalRecordModel`, and `originalRecordId` as props However, since these props are not declared in `mediaDialogProps`, so prop validation filters them out of `this.props`. Thus they are `undefined` in the MediaDialog. Thus they are not passed to the AI chat launcher. Thus ai has to ask user about product name. This commit registers these props on the `mediaDialogProps` schema in the `ai module patch, preventing Owl from stripping them. task-6365588 **Community counterpart: https://github.com/odoo/odoo/pull/273676** Forward-Port-Of: odoo/enterprise#123050
When an outgoing email fails, Odoo now shows the configured SMTP server name instead of a blank 'None' value. This makes delivery problems clearer for administrators and support teams, helping them identify which mail server needs attention.
Original PR description
Steps to reproduce: 1. Run a local SMTP server that responds with a server error. The server file is provided in the task [refuse_smtp.py](https://github.com/user-attachments/files/27166855/refuse_smtp.py) 2. Create an outgoing server for this SMTP server 3. Send an email Issue: The delivery failure reason displays Mail delivery failed via SMTP server 'None' instead of the configured server name. Cause: ir.mail_server.send_email() builds the failure message from the smtp_server argument, but in the common path the mail is sent via mail_server_id. In that case, the actual SMTP server is resolved in connect(), while smtp_server remains unset, so the error message shows None. Solution: Store the resolved server label on the SMTP connection when opening it, and reuse that value when formatting send failures. opw-6139168 Forward-Port-Of: odoo/odoo#280750 Forward-Port-Of: odoo/odoo#261776
This fix ensures that when a payment is unreconciled, the related cash basis tax reversal is dated in the same reporting period as the original tax entry. This prevents tax reports from showing mismatched amounts across different months, keeping period totals accurate.
Original PR description
When unreconciling a payment from an invoice with a cash basis tax, the tax cash basis (CABA) entry is reversed. The reversal is supposed to land in the same period as the origin entry so the tax…
When unreconciling a payment from an invoice with a cash basis tax, the tax cash basis (CABA) entry is reversed. The reversal is supposed to land in the same period as the origin entry so the tax report nets to zero for that period. Steps to reproduce: - Enable cash basis and create a cash basis tax (exigibility on payment) - Post an invoice dated in the past with that tax - Reconcile a bank statement line to the invoice - Resequence the cash basis entry so the month is dropped from the name (CABA/08/2026/0001 -> CABA/2026/0001) - Unreconcile the statement line Issue: The reversal CABA entry created on the last unreconcile is dated today instead of the origin entry's month. In the tax report the original tax amount stays in the statement's month while the reversal amount appears in the current month, so the two no longer cancel out. Analysis: While under a monthly journal sequence a past date returns the last day of that month, under a yearly sequence a past date within the current year returns the latter between the move date and today, moving the reversal out of the origin period. opw-6301553 Forward-Port-Of: odoo/odoo#284840 Forward-Port-Of: odoo/odoo#281250
Rental order lines created from the rental schedule now keep the normal product name, such as "Bike", instead of adding stock quantity details meant only for schedule rows. This prevents confusing descriptions on rental orders while still showing availability information where it is useful in the schedule view.
Original PR description
Versions -------- 19.0 and later Steps ----- - Install `sale_stock_renting`. - Go to Rental > Orders > Rental Schedule. - Create a new rental order line from a cell of the gantt view, on a row…
Versions -------- 19.0 and later Steps ----- - Install `sale_stock_renting`. - Go to Rental > Orders > Rental Schedule. - Create a new rental order line from a cell of the gantt view, on a row grouped by a storable rentable product. Issue ----- The first line of the description of the created line is named "Bike (3 items)" instead of "Bike". Cause ----- The `display_name` override adding that quantity is keyed on the `in_rental_schedule` context key. That key is set on the `action_rental_order_schedule` action itself, so it is part of the search context and is propagated to every record, dialog and dropdown opened from the schedule, while it is only meant to flag that we are in the schedule (default values conversion, hidden onchange buttons, group expansion, ...). Solution -------- Introduce a dedicated `display_renting_stock_quantity` context key and depend on it instead when fetching data to build the gantt rows, leaving the records opened from the schedule with their regular display name. Forward-Port-Of: odoo/enterprise#130651 Forward-Port-Of: odoo/enterprise#130322
The emoji picker in Discuss now stays stable when users select emojis during a search and then clear the search field. This prevents an unexpected crash, making chat interactions smoother and more reliable.
Original PR description
Steps to reproduce: - open Discuss, open any chat, open the emoji picker (no 'Frequently used' emojis) - search a term and select emojis without closing the picker (shift+click on desktop, plain…
Steps to reproduce:
- open Discuss, open any chat, open the emoji picker (no 'Frequently used'
emojis)
- search a term and select emojis without closing the picker (shift+click on
desktop, plain click on mobile)
- clear the search with backspace
=> traceback: 'Cannot read properties of null (reading
`getBoundingClientRect`)' in adaptNavbar().
This happens because when we clear the search input it calls
`highlightActiveCategory()`, which sets `categoryId` to the topmost category of
the grid, which is now the 'Frequently used' category (sortId 0), added to the
picker since the emojis we just picked updated the recent state. To update the
navbar, `currentNavbarPanel` then looks for the panel holding it in
`emojiNavbarRepr`, but that representation is only built in `adaptNavbar()`,
which runs on mount and from the `ResizeObserver` only, so it was built without
the 'Frequently used' category and no panel contains it. It returns undefined,
the navbar renders empty, its size change wakes the `ResizeObserver`, and
`adaptNavbar()` crashes on querySelector('.o-Emoji').getBoundingClientRect()`.
This commit solves the issue by rendering the `recentEmojis` from a snapshot
taken when the picker is opened, so they are not added to the picker while the
while `emojiNavbarRepr` does not contain their category id.
partial backported PR: https://github.com/odoo/odoo/pull/281104
Task-[6204249](https://www.odoo.com/odoo/project/1519/tasks/6204249)
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#287126
Forward-Port-Of: odoo/odoo#284372Vendor bills can now correctly create assets that do not require depreciation. This removes an unnecessary restriction, helping accounting teams record these assets without manual workarounds.
Original PR description
This commit fixes the ability to create no depreciation assets from vendor bills. Previously, a condition on the depreciation account and expense account restricted the asset creation. backport of https://github.com/odoo/enterprise/pull/123070 task-6283929 opw-6540498 Forward-Port-Of: odoo/enterprise#130653
Accounting dashboard KPI calculations now use the right date periods when converting values across currencies. This prevents errors when viewing companies with different currencies and helps ensure profitability and cashflow figures use appropriate exchange rates.
Original PR description
Multicurrency KPI computation requires date bounds to determine the applicable consolidation rates, without them selecting companies with different currencies raises a keyerror on date_to. Use the fiscal year dates for profitability KPIs and the rolling 12-month period for the cashflow one. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Invoices linked to Malaysian MyInvois documents now continue to show their final status when a submission is cancelled or invalid. This avoids confusion where invoices appeared as if they had never been sent, while still allowing users to resend when appropriate.
Original PR description
`l10n_my_edi_state` on the invoice was left empty whenever the related document wasn't in an "active" state (`valid`/`rejected`/`in_progress`), even once it reached a terminal outcome like…
`l10n_my_edi_state` on the invoice was left empty whenever the related document wasn't in an "active" state (`valid`/`rejected`/`in_progress`), even once it reached a terminal outcome like `cancelled` or `invalid`. As a result, the form and list view showed no MyInvois status at all for those invoices, making them look like they were never sent to MyInvois - even though the underlying `myinvois.document` clearly was. Instead of deriving `l10n_my_edi_state` purely from the active document, fall back to a cancelled/invalid document when no active one exists, so the invoice always reflects its real MyInvois status. Since the state can now be `invalid`/`cancelled` (truthy) instead of always empty, every place that used to treat a falsy `l10n_my_edi_state` as license to send/resend is updated to also allow `invalid`/`cancelled`, since those are equally free to resend: `_compute_show_reset_to_draft_button`, `action_l10n_my_edi_send_invoice`, and the "Send To MyInvois" button/field visibility in the view. `l10n_my_invoice_need_edi` also used `l10n_my_edi_state` in its computation, purely to exclude `rejected` invoices (which still have an active document blocking a new send). That state check is now handled directly by each caller instead: the field is renamed to `l10n_my_edi_is_applicable` and reduced to the structural question of whether MyInvois applies to the invoice at all (posted, MY, proxy user configured), while `_compute_highlight_send_button` checks `l10n_my_edi_state != 'rejected'` explicitly. task-6442567
This fixes an issue where demo data could not be installed when the password policy module was active. Businesses can now set up demo or test databases more reliably without being blocked by default demo user credentials.
Original PR description
If auth_password_policy, demo data cannot be installed due to demo:demo user
Checkout step labels are now preserved when website checkout steps are copied during website setup. This prevents customer-facing checkout steps from showing an unwanted “(copy)” suffix, keeping the buying flow clean and professional.
Original PR description
Following PR: https://github.com/odoo/odoo/pull/272177, char fields "name" now append ["(copy)" by default](https://github.com/odoo/odoo/blob/b84ffce402d3fd12e3dd9521b248b15336763a76/odoo/orm/fields_textual.py#L503) on copy. As checkout steps names are generated from generic records at website creation, we want to keep their original name. opw-6538023
Warehouse moves created by push rules now use the most precise source location available, including sublocations when relevant. This helps stock transfers and picking records better reflect where items actually moved from, reducing location mismatches in inventory operations.
Original PR description
This PR fixes the moves (and their picking) `location_id` to be more accurate after applying push rules on the moves. Before this PR: The new move introduced from push rules (and its new picking)…
This PR fixes the moves (and their picking) `location_id` to be more accurate after applying push rules on the moves. Before this PR: The new move introduced from push rules (and its new picking) would have the `location_id = old_move.location_dest_id` which could be a parent of the location_dest_id of the old move_lines which is more accurate. For example, if a move has a `location_dest_id = 'stock'` and the user changes the move_lines of that move so that `move_lines.location_dest_id = 'stock/sublocation'`. When push rules are applied on the move_lines, `new_move.location_id = old_move.location_dest_id = 'stock'`. But, it should be `new_move.location_id = 'stock/sublocation'`. After this PR: The new move now (and its picking) will have the `location_id` set as the `rule.location_src_id` or `old_move.location_dest_id` just in case the `old_move.location_dest_id` is a sublocation of `rule.location_src_id` which gives a more accurate source location for the move and the picking. Task-6226781
Pressing Escape in a date or time picker now discards any typed changes and restores the previous value instead of saving the edit. This makes the behavior consistent with other dropdown fields and helps prevent accidental date changes; Ctrl+Enter now behaves like Enter by saving and closing.
Original PR description
Steps to reproduce: - Click in the input of a datetime picker (with an existing value) - Manually edit the text in the input - Press Escape Current behavior: - The manually typed value is parsed and…
Steps to reproduce: - Click in the input of a datetime picker (with an existing value) - Manually edit the text in the input - Press Escape Current behavior: - The manually typed value is parsed and validated, exactly as if Enter had been pressed instead. Expected behavior: - Escape should discard the edit and restore the field's previous value, closing the picker without applying any change. This is how other dropdown-based fields (e.g. many2one) behave. Solution: - On Escape, reset the input(s) to the current (unedited) value instead of parsing the typed text. If the popover is open, let its own "closeOnEscape" hotkey close it (avoids a double-close race with our own close call); otherwise close/apply directly, since there is no such hotkey to rely on. Also, Ctrl+Enter had a dedicated behavior: it validated the typed value and re-opened/kept the picker open, refreshing its content to reflect the newly entered date. This is removed, so Ctrl+Enter now behaves like a plain Enter (validates and closes). task-6537497 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fixes an inventory issue where moving stock stored in a package that was already reserved for delivery could fail with an access error. Warehouse users can now relocate these packaged quantities without being blocked, improving day-to-day stock management reliability.
Original PR description
**Issue** If a move's package is already reserved, relocating that move raises an AccessError. **Steps to reproduce** - Activate the "Packages" feature in Inventory settings. - Activate track…
**Issue** If a move's package is already reserved, relocating that move raises an AccessError. **Steps to reproduce** - Activate the "Packages" feature in Inventory settings. - Activate track localization in settings - Create a new storable product. - Using an inventory adjustment, add some quantity of that product in Stock, in a new package X. - Create a sales order for that product and confirm it, so the quantity in Stock gets reserved. - Go to Inventory > Reporting > Locations. - Select the quant and try to relocate it, e.g. to WH/Input. -> Raises an AccessError: "Failed to write field stock.package.picking_ids" **Cause** Relocating a quant creates a move: https://github.com/odoo/odoo/blob/b9eb72eb1d3be841396cd5dcce827ec88ed9ee31/addons/stock/models/stock_quant.py#L1531 which creates a new move line without a `picking_id`: https://github.com/odoo/odoo/blob/b9eb72eb1d3be841396cd5dcce827ec88ed9ee31/addons/stock/models/stock_quant.py#L1276-L1287 Since both move lines (the new one and the one linked to the SO delivery) share the same `result_package_id`, in `_compute_picking_ids`, both move lines are grouped: https://github.com/odoo/odoo/blob/b9eb72eb1d3be841396cd5dcce827ec88ed9ee31/addons/stock/models/stock_package.py#L174-L176 Thus, two "pickings" end up associated with the package: the SO's, and `None`. While setting those pickings on the package, it tries to access them: https://github.com/odoo/odoo/blob/b9eb72eb1d3be841396cd5dcce827ec88ed9ee31/addons/stock/models/stock_package.py#L182 https://github.com/odoo/odoo/blob/b9eb72eb1d3be841396cd5dcce827ec88ed9ee31/odoo/orm/fields_relational.py#L1497-L1503 And since `self` isn't just `None`, this check won't be skipped: https://github.com/odoo/odoo/blob/b9eb72eb1d3be841396cd5dcce827ec88ed9ee31/odoo/orm/models.py#L4152 This eventually raises an AccessError since `None` gets filtered out by `filtered_domain`: https://github.com/odoo/odoo/blob/b9eb72eb1d3be841396cd5dcce827ec88ed9ee31/odoo/orm/models.py#L4154-L4156 https://github.com/odoo/odoo/blob/b9eb72eb1d3be841396cd5dcce827ec88ed9ee31/odoo/orm/fields_relational.py#L1504-L1505 opw-6427070 Forward-Port-Of: odoo/odoo#283937 Forward-Port-Of: odoo/odoo#282209
The website builder's automated checks were adjusted to handle a new way Chrome reports background image sizing. This helps keep quality checks reliable across browser versions without changing what users see or do.
Original PR description
In Chrome 152, single-value `background-size` properties may be serialized or expanded to include implicit dimensions (e.g., appending `auto` like `100px auto`), causing strict exact-string test assertions to fail. This commit updates `website` builder test expectations to use regex prefix matching or substring inclusion so tests remain reliable across different Chrome versions. runbot-946570 Forward-Port-Of: odoo/odoo#286094 Forward-Port-Of: odoo/odoo#285591
This fixes an issue where changing a subcontracting manufacturing order from a later delivery could incorrectly update quantities on earlier deliveries. Each new subcontracting order is now linked only to its own delivery, helping keep purchase and delivery records accurate.
Original PR description
**STEP TO REPRODUCE** 1. Create a purchase order for a subcontracted product. 2. validate the picking. 3. Return to the PO, and increase the purchased qty and save, this should create a new picking. 4. On the new picking, click on the smart button to see the subcontracting MO details. 5. Change the product quantity on the MO and save. 6. Return to the first picking, and notice the delivered quantity was changed, this should not be the case. **CAUSE** When creating a new MO, its `move_finished_ids` is linked to the moves of all previous pickings when we create the MO. It should only be linked to the new picking move. opw-6320704 Forward-Port-Of: odoo/odoo#284605 Forward-Port-Of: odoo/odoo#271556
This fix updates a stock test so it searches for the exact product name instead of a broader term. This prevents unrelated products from being selected during automated checks, improving reliability without changing everyday user workflows.
Original PR description
When searching for the product created in the test we were only searching for "Serial" but another product with this word in the internal reference was showing up alone. To fix this we now look for the exact product name to avoid finding another product. The other matching record was introduced in this commit : https://github.com/odoo/enterprise/commit/6d4f4ec471d0d20c4deae5ad5d4fd4f803c20933 runbot-242820 Forward-Port-Of: odoo/odoo#284499
Map location lookups now finish saving even if a user leaves the map view before the lookup completes. This avoids losing coordinates and reduces repeat requests to external, rate-limited location services.
Original PR description
Prevents discarding geocoded coordinates when navigating away from the map view before asynchronous requests complete. Previously, caching calls used a component-scoped ORM service that threw an uncaught "Component is destroyed" error upon unmount. Decoupling the caching write from the component's lifecycle preserves fetched coordinates and avoids duplicate rate-limited API requests. task-6535656
Map popovers now correctly follow whether editing is enabled or disabled for a map view. This prevents users from being blocked from editing when the view is configured to allow it, improving consistency with other Odoo views.
Original PR description
MapPopover.readonly reads model.metaData.canEdit, but it was never set: canEdit was missing from modelParams, so it was always undefined and the popover was permanently readonly regardless of the edit attribute on the arch. Read canEdit from archInfo.activeActions.edit when building modelParams, mirroring gantt_arch_parser and calendar_arch_parser. Task-6537184
Restaurant orders edited on one device will no longer be skipped during synchronization after another device refreshes the same table. This helps ensure added order lines are saved and shared correctly across point-of-sale devices, reducing the risk of lost sales or service errors.
Original PR description
Steps to reproduce: - Device A opens table 10 and adds a product - Device B opens table 10, then goes back to the floor plan - Device A goes back to the floor plan => The lines added on A are lost, they are never synced to the database, nor to the other device When B triggers a synchronisation, A reads the open orders from the server. The local lines of A are kept, but `setup`, which is also called when a record is updated, resets the dirty flag of the order. Going back to the floor plan calls `syncAllOrders`, which filters the order out because it is not dirty anymore, so the lines are never sent. The dirty flag is now kept when the record is updated with server data, since that data does not contain the changes made locally and must be synced in the next synchronization call task-id: 6486258 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286279 Forward-Port-Of: odoo/odoo#284701
The timer now excludes timesheet entries that are not linked to a project when loading systray timer data. This prevents irrelevant or incomplete entries from appearing in the timer, making time tracking clearer for users.
Original PR description
exclude AAL without a project when loading systray timer data task: 6538364 Forward-Port-Of: odoo/enterprise#130515
Early payment discount entries now preserve the original invoice line cost allocation for all discount calculation methods. This prevents accounting details from being lost when invoices with mixed or excluded discount handling are paid early.
Original PR description
_get_invoice_counterpart_amls_for_early_payment_discount_per_payment_term_line only split the early payment discount amount per invoice line (and thus preserved each line's own analytic distribution)…
_get_invoice_counterpart_amls_for_early_payment_discount_per_payment_term_line only split the early payment discount amount per invoice line (and thus preserved each line's own analytic distribution) when the payment term's early_pay_discount_computation was "included". For "mixed" and "excluded", it instead built a single counterpart line, discarding the analytic distribution of the invoice lines. Compute the per-invoice-line base amounts (and the corresponding price_unit for "mixed") for all three computations, keeping only the tax calculation restricted to "included". This way "mixed" and "excluded" discount entries now keep the analytic distribution of the invoice line they come from, while behavior for "included" is unchanged. Steps: - Create 3 payment terms with EPD, each one with a different `early_pay_discount_computation` setting - For each payment terms, create one invoice with two lines, only one having an analytic distribution - Confirm and pay the 3 invoices (early payment, discount applied) Issue: For 'mixed' and 'excluded', the discount line is the sum of the discount from the 2 invoice lines, and the analytic distribution is lost. opw-6380278 Forward-Port-Of: odoo/odoo#286816 Forward-Port-Of: odoo/odoo#282541
VoIP text-to-speech sounds now have to be generated before they can be saved, ensuring the saved text and voice match the actual audio users will hear. This prevents incomplete or outdated audio settings from being saved and makes call flow setup more reliable.
Original PR description
Creating a text-to-speech sound did not require its audio to be generated. It was therefore possible to save a sound whose text and voice did not match any audio file. Moreover, the Generate object button saved the form before generating the audio. This required specific reload logic in call flow dialogs and could persist incomplete values prematurely. Generate the audio as a preview and update the form's draft with the result instead of saving the record through an object action. Store the text and voice used for the generation, and prevent saving when they no longer match the current values or when no generated audio is present. Also discard an asynchronous generation result if the text or voice was changed while the request was running, and remove the now-unnecessary call flow reload logic.
Accounting users who are not administrators can now view and select email templates when sending manual payment reminders. This prevents an access error in the reminder flow, helping teams send customer follow-ups without needing admin permissions.
Original PR description
**Steps to reproduce:**
1. Log in as demo user
2. Go to Accounting > Customers > Invoices
3. Select at least one invoice and click on "Send Reminder"
4. Attempt to change or view the available choices in the "Email Template" field.
**Issue:**
An AccessError is raised:
`You are not allowed to access 'Model' (ir.model) records.`
**Cause:**
The view domain on `template_id` was set to `[('model_id.model', '=', 'res.partner')]`. Traversing `model_id.model` forces the ORM to evaluate security permissions on the `ir.model` relation, which fails for non-admin users.
opw-6452738
Forward-Port-Of: odoo/enterprise#129966When selecting a private city on an employee address, the state and ZIP code now appear immediately instead of only after saving. This makes address entry clearer and reduces the chance of incomplete or confusing employee address information.
Original PR description
Picking a city didn't fill in state and zip until you saved. Added an onchange so it happens live, same as we already do for state/country. Task 6482304
Fixed an issue where card views could stop refreshing correctly after the first reload. This helps users see up-to-date information consistently without needing extra manual refreshes or workarounds.
Original PR description
`this.key` is the signal function, so `this.key + 1` concatenates its source and `set` stores that same string on every reload: the first reload changes the key and re-creates the Record, the next ones are no-ops. Introduced in odoo/odoo#260098 Forward-Port-Of: odoo/odoo#286988
This fixes the messaging menu so it explicitly opens the Chats tab instead of relying on a fallback behavior. It makes the user experience more reliable and reduces the chance of future tab-order changes causing the menu to open incorrectly.
Original PR description
Before this commit, the systray state is inserted with `activeTab: MENU_TABS.CHATS`, a name no module defines, so the value is undefined and the state links no tab at all. This happens because each module names its own tabs, and the discuss one declares `MENU_TABS.CHAT`. The eager compute of `activeTab` hides the mistake: with no tab to keep, it falls back to the first visible tab, which is Chats whenever it is shown, as its sequence is the lowest. This commit inserts `MENU_TABS.CHAT`, so the state says which tab it opens on rather than depending on the sequences around it.
This fixes Saudi localization issues around additional customer identifiers used for electronic invoicing. Businesses can now better record required buyer IDs, including for non-Saudi contacts, helping invoices meet Saudi compliance requirements.
Original PR description
This commit fixes the issues with multi id implementation of `l10n_sa_edi`. Before this PR: - The additional identifiers for `l10n_sa` were declared in `account`. - The `slice` function in js had wrong arguments, `slice(10)`. - `l10n_sa_invoice_type` was not getting updated when the company status (`is_company`) of the partner was updated. - `SA_OTH` additional_identifiers was not visible to non-saudi contacts. After this PR: - The additonal identifiers are now moved into `l10n_sa`. - The `slice` function has been removed. - Added an onchange to populate Saudi Arabia TIN. - Add test cases for l10n_sa additional identifiers - Add test cases for l10n_sa_edi additional identifiers - Added `copy=False` for `l10n_sa_invoice_type` and added `is_company` in dependencies - `SA_OTH` is now visible to non saudi contacts. task-6413445 task-6319117 Forward-Port-Of: odoo/odoo#270776
Fixed a typo in the Italian electronic invoicing withholding tax reason text. This improves the accuracy of tax-related wording shown or reported by the Italian localization without changing business processes.
Original PR description
Correction of a typo in italian withholding tax reason. opw-6514615 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284992
This fix ensures Saudi Arabia tax tag updates are applied during Odoo 19 upgrades. It prevents VAT tax grids and invoices from keeping outdated tax tags, reducing the need for manual correction after migration.
Original PR description
**Issue:** During migration to Odoo 19, the SA tax tag migration logic is present in: "migrations/2.1/pre-migrate.py" was not executed during the migration of databases because this: * SA compact tax…
**Issue:** During migration to Odoo 19, the SA tax tag migration logic is present in: "migrations/2.1/pre-migrate.py" was not executed during the migration of databases because this: * SA compact tax tags were not renamed * VAT tax grids still use old tags * Localization reload was partially updating taxes * manual intervention was required Added logs/debugging in: * 2.1/pre-migrate.py * 2.1/end-migrate.py * 2.2/end-migrate.py - Verified in both local and customer databases that only the 2.2 migration path was executed during upgrade, while the 2.1 migration scripts were skipped because the Odoo 19 manifest upgrade path already targeted the 2.2 migration version. - 19:https://github.com/odoo/odoo/blob/67510fd36f7af31f83ef110602f9922ed5a43024/addons/l10n_sa/__manifest__.py#L6 **Solution:** - Bumped the l10n_sa module version to 2.3 to apply these changes to databases that are already in production. - Moved `migrations/2.1/pre-migrate.py` to `migrations/2.3/pre-migrate.py` to ensure the SA tax tag migration logic is executed during the `2.3` upgrade flow. - Moved `migrations/2.2/end-migrate.py` to `migrations/2.3/end-migrate.py` to align with the `2.3` version bump and refresh the SA tax mappings correctly during migration. * SA tax tags migrate correctly * VAT tax grids update automatically * invoices use new tags correctly * No manual localization reload required OPW - [6117408](https://www.odoo.com/odoo/project/70/tasks/6117408), [6224788](https://www.odoo.com/odoo/project/70/tasks/6224788) Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#264571
This fixes an issue where editing only the analytic details of a bank reconciliation line could be blocked by accounting lock date rules. Users can now make these analytic updates without being incorrectly stopped, while lock date protections remain in place for other accounting changes.
Original PR description
In the case of the bank rec widget, when modifying a line, we actually unlink it and create a new one. In that case, modifying the analytic would trigger the lock date error. But user should be allowed to modify the analytic all the time. In the edit of the bank rec widget, we add a context key that will be added if analytic distribution is the only key modified. task-6397993 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277260
New database installation tests now skip older AI App modules and their connector modules. This keeps fresh installations aligned with the newer AI Agentic app while preserving the legacy modules for existing upgraded databases.
Original PR description
Exclude AI App and its bridge modules from fresh-install builds. They are kept for upgraded databases only; new databases use AI Agentic. task-id-6497307 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Fixed an issue that could leave Ecuadorian electronic invoicing withholding totals blank in the tax totals widget. This helps users see the expected withholding amounts reliably and avoids errors when reopening or refreshing the document view.
Original PR description
TaxTotalsComponent now declares its totals as a computed, so formatData runs inside that computed's own getter. TaxTotalsComponentForWithhold still overrides formatData to assign this.totals directly, which overwrites the computed from within it: the getter returns undefined, so the table's t-if hides it and the widget renders empty, and every later read raises "this.totals is not a function" because this.totals is now a plain object. From: odoo/odoo#270245. Forward-Port-Of: odoo/enterprise#130691
Bank reconciliation edits that only change analytic information will no longer be blocked by lock date checks. This lets users update analytic allocations when needed without disrupting accounting controls for other changes.
Original PR description
In the case of the bank rec widget, when modifying a line, we actually unlink it and create a new one. In that case, modifying the analytic would trigger the lock date error. But user should be allowed to modify the analytic all the time. In the edit of the bank rec widget, we add a context key that will be added if analytic distribution is the only key modified. task-6397993 Forward-Port-Of: odoo/enterprise#124852
This change rolls back a recent database connection handling update because it caused connection usage to spike on gevent servers. Reverting it helps stabilize server resource usage and reduces the risk of performance issues for users relying on real-time features.
Original PR description
This reverts commit 11e76ba8042648596dc0a7c731a78dd786e36884 and PR #285423 The connection usage on the gevent server is spiking. Forward-Port-Of: odoo/odoo#287008
Time off types that are not available for time off no longer show a misleading allocation balance such as (0/0). This keeps payroll and time off screens cleaner and avoids confusion for users reviewing leave-related entries.
Original PR description
**Issue:** When a user deselects the `time_off_selectable` field on a Time Off Type, the `requires_allocation` field is hidden from the view but retains its default background value of `True`. Because the system still evaluates it as true, the `display_name` appends a misleading allocation ratio of `(0/0)` next to the time off type's name. **Solution:** Updated the `_compute_display_name` method to account for the `time_off_selectable` state. The allocation ratio `(0/0)` is now only calculated and appended to the display name **if the time off type is both selectable for time off *and* requires allocation.** Before: <img width="469" height="413" alt="image" src="https://github.com/user-attachments/assets/469fc063-23d9-46a2-9367-8f3bf4ef7312" /> After: <img width="418" height="392" alt="image" src="https://github.com/user-attachments/assets/030451b2-b9cf-4954-a598-01d9846c738e" /> task-6487681
Creating a new CRM stage no longer shows an unnecessary warning about recalculating opportunities. The warning is now reserved for editing existing stages, reducing confusion for CRM users while keeping the helpful alert where it matters.
Original PR description
Changing whether a CRM stage is won may trigger the recomputation of its opportunities. An onchange warning was added to inform users about this potentially expensive operation. However, the warning was also displayed when creating a stage because the onchange was triggered while initializing the form. Fix: Only display the warning when editing an existing stage, as it's useless to show this warning when creating a new stage. Task-6424174 Forward-Port-Of: odoo/odoo#284679
This fixes an error that could stop Website SEO content from being updated with AI when the AI agent used certain document sources. Businesses can now use those documents reliably in AI-assisted SEO updates without the process crashing.
Original PR description
### Problem When an AI agent includes a document source whose underlying `ir.attachment` has `res_field` set (e.g., an invoice PDF generated from a Sale Order), triggering **Update With AI** from…
### Problem
When an AI agent includes a document source whose underlying `ir.attachment`
has `res_field` set (e.g., an invoice PDF generated from a Sale Order),
triggering **Update With AI** from **Website → Site → Optimize SEO**
raises a `KeyError` in `_build_rag_context`.
### Steps to Reproduce
1. Open the **AI** app.
2. Configure the **Odoo Agent**.
3. Add a source → **Add From Documents**.
4. Select a document whose underlying `ir.attachment` has `res_field` set
(e.g., an invoice PDF generated from a Sale Order).
5. Go to **Website → Site → Optimize SEO**.
6. Click **Update With AI**.
7. Observe the following error:
```
KeyError: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
```
[Video](https://drive.google.com/file/d/1AAg0AvC3TRQzMLhI9hWFuSarOTHzQE-b/view?usp=sharing)
### Root Cause
In `ai/models/ai_agent.py`, `_build_rag_context()` retrieves the
`ai.agent.source` records corresponding to the embeddings by searching on the
attachment checksum:
```python
agent_sources = self.env["ai.agent.source"].search([
("attachment_id.checksum", "in", embeddings_attachment_checksums),
("agent_id", "=", self.id),
])
```
This domain traverses `attachment_id.checksum`, which internally calls
`ir.attachment._search()`.
As part of the standard attachment search behavior,
`ir.attachment._search()` automatically injects a
`('res_field', '=', False)` filter unless:
- `skip_res_field_check=True` is set in the context,
- the domain explicitly references `id` or `res_field`, or
- `bypass_access` is enabled.
```python
domain = Domain(domain)
if (
not self.env.context.get("skip_res_field_check")
and not any(d.field_expr in ("id", "res_field") for d in domain.iter_conditions())
and not bypass_access
):
disable_binary_fields_attachments = True
domain &= Domain("res_field", "=", False)
```
[Reference](https://github.com/odoo/odoo/blob/19.0/odoo/addons/base/models/ir_attachment.py#L630)
Because of this implicit filter, attachments with `res_field` set are excluded
from the search. Consequently, `agent_sources` does not contain all the sources
corresponding to the retrieved embeddings.
Later, `_build_rag_context()` builds a checksum-to-source mapping:
```python
source_map = {
source.attachment_id.checksum: source
for source in agent_sources
}
for embedding in similar_embeddings:
checksum = embedding.attachment_id.checksum
agent_source = source_map[checksum]
```
Since `source_map` is built from the incomplete `agent_sources` recordset, it is
missing entries for attachments filtered by `ir.attachment._search()`.
However, `similar_embeddings` still contains embeddings for those attachments.
As a result, the lookup:
```python
agent_source = source_map[checksum]
```
raises a `KeyError`.
### Solution
Bypass the implicit `res_field` filter when searching `ai.agent.source`:
```python
agent_sources = (
self.env["ai.agent.source"]
.with_context(skip_res_field_check=True)
.search([
("attachment_id.checksum", "in", embeddings_attachment_checksums),
("agent_id", "=", self.id),
])
)
```
This ensures that all `ai.agent.source` records matching the requested
attachment checksums are returned, including those referencing attachments with
`res_field` set. As a result, `source_map` contains all expected entries and
`_build_rag_context()` no longer raises a `KeyError`.
opw-6379816
Forward-Port-Of: odoo/enterprise#129999
Forward-Port-Of: odoo/enterprise#125780This fixes a website shop error that could occur when all variants of a product were deleted. The shop now falls back to the main product information for unit pricing, so customers can continue browsing without encountering an error.
Original PR description
Currently, an error occurs when user deletes all the variants of a product and opens the website raises an error. Steps to replicate: - Install `website_sale`, open settings and turn on `Product…
Currently, an error occurs when user deletes all the variants of a product and opens the website raises an error. Steps to replicate: - Install `website_sale`, open settings and turn on `Product Reference Price` and `Product Variants`. - Create a new product `test` , give an attribute and 2 values. - Click on the `Variants` smart button, select all and delete. - Publish this produce in website and open shop on website. Error: ``` ValueError: Expected singleton: product.product() ``` Cause: - Issue occurs after a recent addition of a feature that shows product's unit price on website (check [PR]). - As the user deleted all the variants of the product `test`, when trying to get the unit price of the product's variants [1] causes this error to occur. Solution: - If the product doesnt have any variants we should get the unit price from the product template itself. [PR]: https://github.com/odoo/odoo/pull/254309 [1]: https://github.com/odoo/odoo/blob/22ede9cd601f54ebf248a7ddace433746f066e68/addons/website_sale/models/product_template.py#L686 sentry-7635385579 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282945
This fix ensures mail-related background data is cleaned up whenever an Odoo app is closed, including apps like Point of Sale and self-ordering that embed mail features. It prevents stale callbacks from accumulating over time, reducing memory use in affected test scenarios by around 38%.
Original PR description
ChatHub's cleanup (the shared `subscribeToStorage` listener) only ran when something explicitly called `store._runDisposeFns()`. Only mail's own test helper did that; any other app embedding…
ChatHub's cleanup (the shared `subscribeToStorage` listener) only ran when something explicitly called `store._runDisposeFns()`. Only mail's own test helper did that; any other app embedding `mail.store` (point_of_sale, pos_self_order, ...) never disposed it, so `subscribeToStorage` kept one stale callback per undisposed ChatHub, unbounded. Hook disposal into the services registry's "CLEANUP" event instead, which Owl already fires on every app teardown regardless of embedding (same pattern as `profiling_service.js`). Converting `storeService` to an Owl plugin using its own `onWillDestroy` (see TODO) would be the cleaner long-term fix. Measured via hoot's [MEMINFO] on the self_order_service suite that exposed this leak, same db/commit, only the fix toggled: | suite | before (MB) | after (MB) | % | |---------------------------------------------------------|------------:|-----------:|-------:| | pos_self_order/services/self_order_service (30 tests) | 253.8 | 155.6 | -38.7% | | pos_online_payment_self_order/self_order_service | 253.1 | 155.0 | -38.8% | | pos_self_order_event/self_order_service | 253.2 | 155.1 | -38.7% | | pos_self_order_iot/self_order_service | 260.1 | 162.0 | -37.7% | | tests done (final) | 251.9 | 153.8 | -38.9% | --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Since [1], we have 2 calls to `_bootstrap_homepage` - one in the `post_init_hook`, and one in `website.create`, causing the menu hierarchy to be duplicated. This doesn't apply to the default website (from base) as there was no `create` method override at the point of creation (website is not installed yet) and the homepage/menu is only created once, by the `post_init_hook`. Steps to reproduce: 1. Install website with demo data. 2. Menus for website 2 are duplicated. Solution: Si
Original PR description
Since [1], we have 2 calls to `_bootstrap_homepage` - one in the `post_init_hook`, and one in `website.create`, causing the menu hierarchy to be duplicated. This doesn't apply to the default website (from base) as there was no `create` method override at the point of creation (website is not installed yet) and the homepage/menu is only created once, by the `post_init_hook`. Steps to reproduce: 1. Install website with demo data. 2. Menus for website 2 are duplicated. Solution: Simply check if the website doesn't have a menu before duplicating it. [1]: https://github.com/odoo/odoo/commit/ae81b6f6074632d1a609387e53f97a61ee6c95f4 task-6030210 Forward-Port-Of: odoo/odoo#286713
The settings screen now hides both the Project field and its label when billing is turned off or Project Planning is enabled. This removes a confusing leftover label and makes the Billable configuration clearer for users.
Original PR description
*: planning_field_service_sale_timesheet,project_timesheet_forecast_field_service_sale ## Before this commit Only the project field was hidden when "Billing" is not enable, or if "Project Planning" is enabled, leaving the "Project" label visible in any case. ## After this commit The label and field are hidden if "Billing" is not enabled, or if "Project Planning" is enabled. task-6478896 Forward-Port-Of: odoo/enterprise#129852
The VoIP module was updated as part of the platform migration to Owl 3. This internal cleanup helps keep VoIP flows compatible with the newer web framework without changing day-to-day user behavior.
Original PR description
As part of the Owl 3 migration, replace **onWillUpdateProps** hook with the appropriate Owl 3 alternatives.
The accounting reports code was updated to use the current supported behavior in Odoo's interface framework. This keeps audit balance report screens compatible with the next OWL version while preserving existing tested behavior.
Original PR description
Replaced `useLayoutEffect` with `useEffect` (from `@odoo/owl`) because `useLayoutEffect` is deprecated in OWL3. The useLayoutEffect refactored in this PR had test coverage — below are some tests that failed when the effect was commented out, and are now passing: - TestAccountReportsTours.test_account_reports_audit_tours (account_reports post-install) see commented-out runbot build: https://runbot.odoo.com/runbot/batch/2748320/build/124302666