Daily updates from Odoo
Tuesday, July 7, 2026
46 changes · saas-19.2
Enhancements to existing features
UK VAT returns now guide users to file through the relevant tax unit when their company belongs to one. The system uses the tax unit VAT number for HMRC connections and submissions, reducing filing errors and ensuring reports are sent under the correct entity.
Original PR description
BEFORE: - Before this commit, when the current company is a member of the tax unit, there is no blocking level error for the user to select the tax unit. - And the vat used while creating a connection to the HMRC or while sending a tax report to the HMRC is of the current company. AFTER: - After this commit, there is one blocking level error, which tells the user that the current company is part of a tax unit, and on confirmation, the tax unit will automatically be selected for the current report. - And if the return contains the data of a tax unit, then the vat set on the tax unit will be considered while establishing the connection and sending the tax report to HMRC. Task-5865605 Forward-Port-Of: odoo/enterprise#122965 Forward-Port-Of: odoo/enterprise#107253
Belgian payroll rules were updated with the new employment bonus parameters taking effect on 1 July 2026 and 1 September 2026. This helps ensure payroll calculations remain aligned with upcoming legal requirements and reduces the risk of incorrect payslips.
Original PR description
Update the employment bonus parameters for 1st July 2026 and 1st September 2026. task-6369633
Belgian payroll calculations now include updated employment bonus parameters taking effect on 1 July 2026 and 1 September 2026. This helps ensure payroll remains aligned with the latest Belgian rules for eligible employees.
Original PR description
Update the employment bonus parameters for 1st July 2026 and 1st September 2026. task-6369633
This change speeds up forum pages by reducing the work needed to display popular tags and match similar posts. For odoo.com, it cuts the time and database load of forum page requests roughly in half, which helps the site stay faster under heavy traffic.
Original PR description
This PR improves the cost of `/forum/my-forum-1/my-slug-1234` by ~48%. This has a huge impact on odoo.com The `/forum/...` routes are the `#1` on odoo.com in terms of absolute count and in terms of…
This PR improves the cost of `/forum/my-forum-1/my-slug-1234` by ~48%. This has a huge impact on odoo.com The `/forum/...` routes are the `#1` on odoo.com in terms of absolute count and in terms of CPU and SQL cost. They are called several million times a day. The average total time for `/forum/my-forum-1/my-slug-1234` goes from ~358ms to ~187ms (sql: 107ms -> 52ms - cpu 250ms -> 135ms) This has been tested by extracting 30k real forum post urls from odoo.com logs and replaying them on a staging server. That day `/forum/...` routes were called 2.8M times ## before <img width="1343" height="122" alt="image" src="https://github.com/user-attachments/assets/2b8264b7-4f26-40a7-a20a-20d478f5a93a" /> ## after <img width="1339" height="124" alt="image" src="https://github.com/user-attachments/assets/7c73aeb0-a4b4-45b8-ae98-093ac70c438e" /> ### First commit before <img width="1857" height="946" alt="image" src="https://github.com/user-attachments/assets/63b9d966-f5fd-4047-b4cb-533b7e9491bc" /> after <img width="1844" height="867" alt="image" src="https://github.com/user-attachments/assets/9494efe0-0b7c-419d-b918-dcfe5e942e63" /> query plan for most used tags as public user: - with the index https://explain.dalibo.com/plan/gbf9fbd358687f3e - without the index https://explain.dalibo.com/plan/da5gg6cd27f67496 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Creating employees will now process future public holiday time entries much faster. This prevents long waits or timeouts when many holidays have been set up far into the future, improving reliability for HR and planning teams.
Original PR description
**Problem:** When creating a new employee, the future timesheets due to public holidays are computed. If the number of public holidays is large (i.e. if the user creates them for each year, several…
**Problem:** When creating a new employee, the future timesheets due to public holidays are computed. If the number of public holidays is large (i.e. if the user creates them for each year, several years in the future), then it takes excessively long and the action may not complete. **Cause:** The pytz method `localize` and comparing times with non-static timezones is done repeatedly and unnecessarily which becomes costly with more records. **Solution:** Only localize the time when absolutely necessary (determining the date of the leave in the calendar timezone). **Performance Stats:** |Record count|Time before|Queries before|Time after|Queries after| |------------|-----------|--------------|----------|-------------| |100 |3.1s |393 |0.8s |117 | |1,000 |22.3s |2,090 |1.5s |183 | |10,000 |Timeout |N/A |6.7s |541 | opw-6087422 Forward-Port-Of: odoo/odoo#270684 Forward-Port-Of: odoo/odoo#263953
This update simplifies the VAT input field in the accounting module, making it easier for users to enter tax ID information. The system now displays the expected VAT format when available and provides a clearer tooltip explaining how to indicate a customer without a tax ID. This improves data accuracy and user experience.
Original PR description
In this commit: - Remove 'or not applicable' and '/ if not applicable' from VAT placeholders. - Display the expected VAT format when available (e.g. BE0477472701). - Leave the placeholder empty when no format is known. - Simplify the tooltip to: 'You can use / to indicate that the customer has no Tax ID.' task-[5005896](https://www.odoo.com/odoo/project/967/tasks/5005896) Forward-Port-Of: odoo/odoo#273344
Resolved issues and error corrections
This fix prevents an error when importing Belgian CODA bank statement files after an update added extra file information. Businesses using Belgian bank statement imports can continue processing statements without interruption.
Original PR description
in this commit: https://github.com/odoo/enterprise/commit/c66995fda83e19b28a38312af8efdc1601881cf0 we did a backport of the extension number. The backport adds the extension number to the return of the _parse_bank_statement_file. With that we have 4 args returned. Without the * we would have the "too many value to unpack" error opw-6362679 Forward-Port-Of: odoo/enterprise#123104
EC Sales List returns are now created separately for each company in a tax unit using that company's own VAT number. This prevents member entities from being incorrectly combined under the tax unit VAT number and supports more accurate compliance reporting.
Original PR description
Issue: The EC Sales List return is currently generated under the tax unit VAT number, consolidating all member entities into a single declaration. Expected: The EC Sales List return must be generated individually per member entity, each under their own VAT number, even when those entities belong to a tax Unit. Fix: Apply tax unit only if report's multi company filter is `tax_units`. Ref: https://github.com/odoo/enterprise/blob/07e8aba8604319747a5925c83576095ce9a63f9e/account_reports/models/account_return.py#L316-L317 task-6069402 Forward-Port-Of: odoo/enterprise#115974
The Hong Kong payroll calculation for payment in lieu of notice now accounts for an employee's actual contract start date instead of assuming a full prior year of service. This helps produce more accurate final payments for employees who have worked less than 12 months, with added tests covering related edge cases.
Original PR description
Currently, the calculation of the payment in lieu of notice is assuming the employee worked a whole 12 months prior to it being paid. This is of course not always going the be case, and when it happens our calculation is often incorrect. We update the salary rule to calculate a more accurate total days (which is no longer based on a fixed 12-month period but takes into account the contract's start date). We also now calculate the number of months more accurately by taking, once again, the contract's start date into account. Also adding a few test cases to test a bit more some special case we didn't yet test correctly. task-6348903 Forward-Port-Of: odoo/enterprise#122580
Mobile self-ordering now uses the same printing approach as kiosk mode, so preparation receipts are correctly sent to kitchen or preparation printers. The update avoids a failing connection method for mobile customers and uses websocket printing through the IoT Box instead, improving order handling reliability.
Original PR description
Self ordering mobile now aligns on kiosk avoiding to update last order changes, which would prevent from printing preparation receipts. This is made possible by the IoT Box allowing to print receipts through websockets. We also take the opportunity to update the `iot_http` service in order to allow updating methods available on the service: it allows us adding a new method to disable longpolling for self ordering mobile, which would always fail, to end up using websocket (clients are not on the same network as the IoT Box).
New planning shifts now default to 8 AM to 4 PM in the user's own timezone instead of being shifted by UTC conversion. This prevents employees in places like Belgium from seeing incorrect default shift times, making schedule creation more accurate and predictable.
Original PR description
Before: When creating a new shift, we set 8 AM - 4 PM as the default hours in UTC. With the timezone in Belgium, this becomes 10 AM - 6 PM. After: Change the timezone of the new shift to match the user's timezone. This will make the hours always be from 8 to 4 (working hours) --- task-6285596
Hong Kong payroll now handles payslips with missing start or end dates without crashing. This prevents interruptions when users edit payslip periods and keeps wage calculations from running on incomplete date information.
Original PR description
Currently, an error occurs when a user removes the payslip date. **Steps to Reproduce:** - Install `l10n_hk_hr_payroll` with demo data. - Switch to the `Hong Kong` company. - Go to `Payroll` >…
Currently, an error occurs when a user removes the payslip date. **Steps to Reproduce:** - Install `l10n_hk_hr_payroll` with demo data. - Switch to the `Hong Kong` company. - Go to `Payroll` > `Payslips` > `Payslips`. - Create a `payslip` and remove the `start` or `end` period. **Error 1:** `TypeError: unsupported operand type(s) for +: 'bool' and 'relativedelta'` **Error2:** `AttributeError: 'bool' object has no attribute 'month'` When a user removes the start or end date of a payslip, the system computes the Average Daily Wage. Based on the payslip dates, it finds the previous year's payslips [1]. If the start or end date is not set, it raises an error [2]. For the second error, when computing whether to include EOY pay, it compares the company's EOY pay date with the end date's month. If the end date is not set, accessing its month raises an error [3]. This commit ensures that when retrieving previous-year payslips, if the start or end date is not set, it returns an empty payslip recordset. It also ensures that when computing whether to include EOY pay, if the end date is not set, `include_eoy_pay` is set to `False`. [1]: https://github.com/odoo/enterprise/blob/ec8a009794863090351d91650aff727e6fbeab7e/l10n_hk_hr_payroll/models/hr_payslip.py#L124 [2]- https://github.com/odoo/enterprise/blob/ec8a009794863090351d91650aff727e6fbeab7e/l10n_hk_hr_payroll/models/hr_payslip.py#L209-L215 [3]- https://github.com/odoo/enterprise/blob/ec8a009794863090351d91650aff727e6fbeab7e/l10n_hk_hr_payroll/models/hr_payslip.py#L141 Forward-Port-Of: odoo/enterprise#120586
A booking availability issue was fixed so appointment types that allow multiple simultaneous bookings can use their configured capacity correctly. This prevents available slots from being blocked after only one booking when capacity management is not enabled.
Original PR description
Previously, the condition which evaluated availability if a conflicting booking existed returned this: `return resource.shareable if self.manage_capacity else True` After a performance improvement commit, it was rewritten into a filter on valid resources, where this was a part of the condition: `not (self.manage_capacity and resource.shareable)` In the original, if manage_capacity was false, we always returned True and later handled capacity using the max_bookings field on the appointment type. In the updated version, if manage_capacity is False, we filter the resource out and only ever allow one booking at a time, regardless of max_bookings This commit updates the condition to act like before Task-6344438
The Timesheets assistant now opens the chronological suggestion view reliably, even when timeline items are not linked to a project. This prevents an error and lets users continue reviewing and taking timesheet suggestions as expected.
Original PR description
Steps to reproduce: - Open the assistant in the Timesheets app. - Click on the chronological view in the suggestion section. Cause: Timeline activity records do not always have a project_id, but the template attempted to access it to determine whether the Take button should be displayed. Fix: Use the record-level allow_timesheets flag instead of accessing project_id, preventing crashes for timeline activity records without a project. issue-https://github.com/odoo/enterprise/pull/122727 task-6368279
The task Gantt view now shows timesheet progress at the correct scale. This fixes misleading progress bars where partially completed work appeared almost invisible, helping teams quickly understand task completion in planning views.
Original PR description
Steps to reproduce: ------------------------------------------- 1. Install the Timesheet module with demo data 2. Go to any FSM task > set allocated hours to 20h 3. Fill the timesheet for the same…
Steps to reproduce: ------------------------------------------- 1. Install the Timesheet module with demo data 2. Go to any FSM task > set allocated hours to 20h 3. Fill the timesheet for the same task for 10h 4. Navigate to FSM > My Tasks > Gantt view Observation: ------------------------------------------- Look at the task on the Gantt chart. The shading is barely visible because it covers only 0.5% of the bar, not 50% Issue: ------------------------------------------- In the commit https://github.com/odoo/odoo/pull/137570/changes/4a93d9aee957dd3feb3db0cb69eb3b8f0f4a4683 The progress field computation was changed from storing percentage values (0-100) to storing decimal values (0-1). Specifically, the `_compute_progress_hours` method was modified. This change was made to standardize the progress field storage format, with the understanding that the UI layer would multiply by 100 when displaying the value. While most views (form, list, kanban, etc.) were updated to multiply the progress by 100 for display purposes, the Gantt view's pill progress bar was missed. Solution: ------------------------------------------- Overrides the `enrichPill` method to multiply the `_progress` value by 100 before it's passed to the template. This ensures the Gantt pill progress bars display correctly without modifying the core web_gantt module. Before --------------------------- <img width="268" height="368" alt="image" src="https://github.com/user-attachments/assets/6d35927f-bd3f-47fc-9101-e2e188d419b8" /> After: -------------------------- <img width="250" height="371" alt="image" src="https://github.com/user-attachments/assets/fe7133e0-26d1-4c5f-b903-48826fda9488" /> opw-6038983 Forward-Port-Of: odoo/enterprise#122899 Forward-Port-Of: odoo/enterprise#111270
This fix ensures the scheduled process for Mexican electronic invoice status checks continues running when there are more documents left to process. Businesses using Mexican localization will no longer see invoices left pending simply because the batch limit was reached.
Original PR description
Steps to reproduce ----------------- - Install l10n_mx_edi; - Switch to the mexican company; - Create 3 invoices for the mexican company (you will need to set an UNSPSC code on the products); - Send them to CFDI; - Go to the scheduled action "Automatic update of state on the SAT" and add "batch_size=2" to the method's parameters; - Manually run the cron; - Only two invoices will be updated, the cron is not retriggered to process the remianing one. Why is it hapening ------------------ We set a limit of batch_size + 1 in the search method, and the cron is retriggered if and only if the number of documents fetched is equal to the batch size, meaning there is no more documents to fetch. This should be triggered if we fetched more documents than the batch size. opw-6328118 Forward-Port-Of: odoo/enterprise#122659
Twitter/X social stream posts now store the reply count provided by the platform. This lets users see comment activity alongside other engagement metrics, giving a more complete view of post performance.
Original PR description
Twitter/X tweet metrics returned by the API include the number of replies in the `public_metrics.reply_count` field. This commit stores that value on social stream posts so the comments count can be displayed alongside other engagement metrics. API Documentation: https://docs.x.com/x-api/fundamentals/metrics#post-metrics Task-6251172 Forward-Port-Of: odoo/enterprise#120182
The task Gantt view now loads correctly when users group tasks by sale order item. This prevents an error caused by an outdated time-planning field name, restoring visibility into task progress for sales-linked projects.
Original PR description
### Steps to reproduce - Install `sale_timesheet_enterprise`. - Go to **Tasks → All Tasks**. - Switch to the **Gantt** view. - Group by **Sale Order Item** (`sale_line_id`). ### Issue A traceback is…
### Steps to reproduce - Install `sale_timesheet_enterprise`. - Go to **Tasks → All Tasks**. - Switch to the **Gantt** view. - Group by **Sale Order Item** (`sale_line_id`). ### Issue A traceback is raised when loading the Gantt view with group by `sale_line_id`: ```text ValueError: Invalid field 'planned_hours' on model 'project.task' for 'planned_hours:sum' ``` ### Root cause The Gantt progress bar computation for the `sale_line_id` grouping performs a `_read_group()` aggregation on the `planned_hours` field of `project.task`. However, `planned_hours` was renamed to `allocated_hours` during the saas-16.5 migration, so the former field no longer exists on `project.task`. As a result, the aggregation raises a `ValueError`. Migration reference: https://github.com/odoo/upgrade/blob/e638c6ce00d9d8936d034ad7130fef51565b9195/migrations/project/saas~16.5.1.2/pre-migrate.py#L10 Issued PR: https://github.com/odoo/enterprise/pull/49685 ### Fix Use `allocated_hours`, the renamed equivalent of `planned_hours`, when computing the Gantt progress bar. This restores the Gantt view when grouping tasks by **Sale Order Item** and prevents the traceback. Forward-Port-Of: odoo/enterprise#122994 Forward-Port-Of: odoo/enterprise#122297
This fixes an issue where the snippet selection dialog in the mailing editor could appear hidden when the AI chatbox was open. Users can now add mailing snippets and continue using save or discard actions without the editor appearing frozen.
Original PR description
When an AI chatbox is active, all non-error dialog overlays are set to be behind the chatbox through their z-index. This causes an issue where the dialog overlay that adds new snippets to a mailing is placed behind the fullscreen mailing editor, preventing its use and freezing the use of some commands (save & discard). This commit restores the snippet dialog's z-index to its original value. Steps to reproduce: - Create a new mailing - Select a builder-enabled theme (such as Events Promo) - Open a new AI chat by clicking the AI icon in the top right - Open the fullscreen editor - Click on the Headers block category task-6321624
This update changes when certain internal tests run so they avoid accounting setup warnings during installation checks. It helps keep automated validation stable without changing day-to-day business features.
Original PR description
Before this commit, the `TestFsmFlowSaleAtInstall.test_fsm_flow` test throws a warning because of chart template in accounting, the reason is because all tests using accounting test class have to be executed in post_install to avoid having unexpected issue. This commit moves the test in post_install and skip the test is `planning_field_service_sale_stock` module is installed because the behavior tested is altered when that module is installed. runbot-error-240998
A small typo in a user interface class was fixed so the meeting/call screen adapts correctly on smaller displays. This helps keep the layout consistent and improves the experience for users on different screen sizes.
Original PR description
--- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274435 Forward-Port-Of: odoo/odoo#274343
This fix prevents an error that could appear when opening the Time Off “By Employee” report for employees in the French company setup. It ensures the report works correctly even when an employee has no working hours calendar configured, avoiding a disruption for users reviewing leave information.
Original PR description
A singleton error appears when opening the "By Employee" report under Time Off. Steps to reproduce: 1)Install the l10n_fr_hr_holidays module. 2)Switch to the French company. 3)Open any employee record. 4)Set Working Hours (resource_calendar_id) to empty. 5)Set Hours Per Week. 6)Create a time off request for any past date. 7)Go to Reporting → By Employee. Task:-6043142 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#264585
This change prevents an error that could occur when searching paid POS orders after one of the employees involved had been archived. It ensures the Point of Sale order loading still works correctly, so users can continue reviewing past orders without interruption.
Original PR description
Steps to reproduce on runbot:
- Enable "Log in with Employees"
- Connect to the POS with an employee
- Process an order
- Go to the backend
- Archive the employee
- Connect to the POS with another employee
- Go to the "Order" tab and search for "Paid" orders
Error:
Odoo Server Error: {archived_employee_id}
[opw-6223243](https://www.odoo.com/odoo/project/49/tasks/6223243)
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#273889
Forward-Port-Of: odoo/odoo#266364We fixed an issue where the buttons for microphone, camera, and hang up could be hidden when joining a call in a mobile browser. The call screen now fits the visible area more accurately, making it easier to control calls on phones and tablets.
Original PR description
Before this commit, joining a call in a mobile browser (Chrome, Safari, ...) would crop the bottom call controls (mic, camera, hang-up, ...) behind the browser's chrome (URL bar / bottom nav). On…
Before this commit, joining a call in a mobile browser (Chrome, Safari, ...) would crop the bottom call controls (mic, camera, hang-up, ...) behind the browser's chrome (URL bar / bottom nav). On mobile, entering the meeting uses the fullscreen overlay with `keepBrowserHeader: true`, so no native fullscreen is requested and the browser UI stays visible. The overlay was sized with the Bootstrap `vh-100` class (`height: 100vh`), and `100vh` resolves to the *large* viewport (as if the URL bar were hidden). Combined with `fixed-top`, the overlay extended past the visible area and pushed the control row off screen. This commit sizes the overlay with `100dvh` (dynamic viewport height) instead, which tracks the currently visible viewport and shrinks while the URL bar is shown, keeping the controls on screen. This is a no-op in native/desktop fullscreen where `dvh == vh`, and matches the `dvh` usage already present in the codebase (welcome page, bottom sheet). task-6353266 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273949
Point of Sale receipts now correctly show line discounts when a product is sold with a percentage reduction. This helps customers and staff clearly see the discounted amount on the printed receipt, matching what was shown during the sale.
Original PR description
Currently, when adding a line discount it does not reflect on the receipt. Steps to reproduce: ------------------- * Add items to the order * For one of them use a line discount (% button) * Pay the order * Generate the receipt > The mention x% discount off on y is not displayed Why the fix: ------------ On the product screen the mention is shown and the value is computed here: https://github.com/odoo/odoo/blob/fc2230fb44dc421fe280d49da9b2d8134e1a0702/addons/point_of_sale/static/src/app/models/accounting/pos_order_line_accounting.js#L54-L66 We can reuse this fonction for the frontend, in the backend we translate it. We don't show this mention for the chosen products of a combo product. opw-6290821
This update fixes a display issue where URL autocomplete suggestions could extend beyond the screen on mobile devices. The suggestions now fit the available width, making it easier to use the link editor without layout problems on smaller screens.
Original PR description
Step to reproduce: - Open Notes - Open the link popover - Type a URL in the URL input field Description of the issue/: - On mobile devices, URL autocomplete suggestions overflow the viewport. Cause: - The autocomplete suggestions container has a max-width of 600px. - On smaller screens, the container does not shrink to fit the available width, causing it to overflow the viewport. Solution: - Add width: 100% to the autocomplete suggestions container so it adapts to the available screen width on smaller devices while still respecting the existing max-width on larger screens. task-6201175 Forward-Port-Of: odoo/odoo#271925 Forward-Port-Of: odoo/odoo#269493
This change prevents a validation error that could happen when users edit subcontracting raw materials by removing one line and adding another in the same step. It helps production recording complete reliably without losing required product information during the save process.
Original PR description
**Issue** In subcontracting, deleting a raw move line and adding a new one in the same editing flow can lead to a validation error during production recording. **Steps to reproduce** - Create a…
**Issue** In subcontracting, deleting a raw move line and adding a new one in the same editing flow can lead to a validation error during production recording. **Steps to reproduce** - Create a subcontracting product with a comp A - Create and confirm a purchase order of that product (with the subcontracting partner) - Open the associated delivery - Open the move details (hamburger button) - Delete the move line linked to the comp A - Create a new move line for a comp B with a quantity of 1 - Record the production -> A validation error occurs: the mandatory field `product_uom_id` is not set. **Cause** The regression comes from this commit: https://github.com/odoo/odoo/commit/54f10b56f577ad9ed5575bd396dba7d20d22fc2e While assigning `move_raw_ids`, the inverse method is triggered: https://github.com/odoo/odoo/blob/9267b2d1a9b2d2d6a33eceab07d572406c68c723/addons/mrp_subcontracting/models/mrp_production.py#L34 At this stage, newly added lines are still virtual records (`line`): https://github.com/odoo/odoo/blob/9267b2d1a9b2d2d6a33eceab07d572406c68c723/addons/mrp_subcontracting/models/mrp_production.py#L38 The previous implementation directly unlinked removed move lines (see commit https://github.com/odoo/odoo/commit/54f10b56f577ad9ed5575bd396dba7d20d22fc2e): https://github.com/odoo/odoo/blob/9267b2d1a9b2d2d6a33eceab07d572406c68c723/addons/mrp_subcontracting/models/mrp_production.py#L40-L43 Which will eventually flush and invalidate all the cache: https://github.com/odoo/odoo/blob/0e78b4fd2ab904f2e12107cb6ff7cc11d512259f/odoo/models.py#L4666 And since `line` is a virtual record (not in db), its associated values will be reset, among those, `product_uom_id`. Later, when the move line is reassigned: https://github.com/odoo/odoo/blob/0e78b4fd2ab904f2e12107cb6ff7cc11d512259f/addons/mrp_subcontracting/models/mrp_production.py#L49 https://github.com/odoo/odoo/blob/0e78b4fd2ab904f2e12107cb6ff7cc11d512259f/odoo/models.py#L5223-L5228 the validation fails because the virtual line no longer contains the required values. **Additional note** An alternative could have been using Command but since this line: https://github.com/odoo/odoo/blob/0e78b4fd2ab904f2e12107cb6ff7cc11d512259f/addons/mrp_subcontracting/models/mrp_production.py#L42 can not be converted to: `Command.set([line.id for line in lines])` because `lines` may also contain virtual records. This causes an invalid quantity for the move. Indeed, even if the command operator would update the quantity on the `move_line` correctly, it won't for the quantity of the `move` because of its associated compute method: https://github.com/odoo/odoo/blob/26ba95ac1c5bbb24975efb1a6f53c1ab47b61532/addons/stock/models/stock_move.py#L399-L400 that relies on `.ids`, which is `[]` on virtual records. Therefore, keep the change minimal. opw-6133281 Forward-Port-Of: odoo/odoo#267279 Forward-Port-Of: odoo/odoo#263058
All-day events synced from Google Calendar will now be stored in a way that keeps them on the correct day for users in every time zone. This prevents dates from appearing one day earlier in Odoo’s list view, while keeping the calendar display consistent.
Original PR description
When Google sends an all-day event, the payload only contains a date (no time), so the inbound sync stores start and stop at 00:00 UTC. The list view renders those Datetime fields in the viewing…
When Google sends an all-day event, the payload only contains a date (no time), so the inbound sync stores start and stop at 00:00 UTC. The list view renders those Datetime fields in the viewing user's timezone, so any user west of UTC sees the previous day. The calendar view stays correct because it reads the date part directly. The rest of Odoo stores all-day events at 08:00 and 18:00 UTC, which keeps the stored datetime inside the same calendar day: https://github.com/odoo/odoo/blob/327ad9b737b0f1d4c547c71a52c45d8433f2b3f4/addons/calendar/models/calendar_event.py#L408-L414 Apply the same 08:00 / 18:00 normalization when building values from a Google all-day payload, so events created on Google match events created in Odoo. Steps to reproduce: 1. Set your user timezone to America/Winnipeg. 2. Connect a Google account and run the calendar sync. 3. In Google Calendar, create an all-day event on January 31. 4. Sync, then open Calendar in list view in Odoo. => Start Date and End Date columns show January 30. Ticket [link](https://www.odoo.com/odoo/project.task/6145880) opw-6145880 Forward-Port-Of: odoo/odoo#271573 Forward-Port-Of: odoo/odoo#262282
Signing up with the same email address in different letter cases will now be treated as the same account. This prevents customers from accidentally creating duplicate logins for one mailbox and makes account creation messages clearer.
Original PR description
Login uniqueness is enforced by a `UNIQUE (login)` constraint that Postgres compares byte for byte, so signing up with foo@example.com and then Foo@example.com produces two separate accounts pointing…
Login uniqueness is enforced by a `UNIQUE (login)` constraint that Postgres compares byte for byte, so signing up with foo@example.com and then Foo@example.com produces two separate accounts pointing at the same real mailbox. https://github.com/odoo/odoo/blob/66a6c16551041543b5addfe846f15e769b4e9afe/odoo/addons/base/models/res_users.py#L274 Even if the DB constraint did catch an exact-case duplicate and `_signup_create_user` re-raised it as a `SignupError`, the controller's friendly "already registered" branch only triggers when the duplicate lookup finds a row, and that lookup goes through `_get_login_domain` with an exact `=` operator. Case variants would fall into the generic "Could not create a new account" branch instead. https://github.com/odoo/odoo/blob/66a6c16551041543b5addfe846f15e769b4e9afe/addons/auth_signup/controllers/main.py#L68-L75 https://github.com/odoo/odoo/blob/66a6c16551041543b5addfe846f15e769b4e9afe/odoo/addons/base/models/res_users.py#L749-L750 `_signup_create_user` now refuses creation when a user with the same email already exists, applying to both b2c free signup and token-based invitations. It raises `UserError` directly so the controller's `except UserError` surfaces the message without a redundant lookup. The check uses `_get_email_domain`, whose base implementation is switched from `=` to `=ilike` over a value escaped via `tools.escape_psql` so `%` and `_` are matched literally rather than as wildcards. Its only existing caller is `reset_password`, which already wants case-insensitive matching. Steps to reproduce: 1. In Settings, set Customer Account to "Free sign up" and save. 2. Log out, then on the login page click "Don't have an account?". 3. Register with foo@example.com. 4. Log out again and click "Don't have an account?". 5. Register with Foo@example.com. => Two distinct user accounts are created for the same mailbox. opw-6199441 Forward-Port-Of: odoo/odoo#263864
This update prevents a validation error when confirming a manufacturing order that uses a component owned by another company branch. It helps users complete production without being blocked by access restrictions on shared product settings.
Original PR description
### Steps to reproduce: - Have a company with a branch say "company1" and "branch" - Create two products: Final product (FP), Component (Comp) - Set the company_id of FP to "branch" and of Comp to…
### Steps to reproduce: - Have a company with a branch say "company1" and "branch" - Create two products: Final product (FP), Component (Comp) - Set the company_id of FP to "branch" and of Comp to "company1" - Associate both products with a product category set to avco in company1 (the field is company dependant) - Create a bom for FP with company_id set to "branch": 1 X Comp - Impersonate a user whose only allowed and default is "branch" - Create and confirm an MO for 1 unit of FP - Set the qty_producing to 1 unit and validate #### > Access Error: Access to unauthorized or invalid companies. ### Cause of the issue: Validating the MO will, validate the component move and set its value: https://github.com/odoo/odoo/blob/f4d079cc5a9c47672cf1a6747bb073e8e74f7350/addons/stock_account/models/stock_move.py#L168-L173 But, in order to determine this value, it is necessary to determine its `property_cost_method`: https://github.com/odoo/odoo/blob/f4d079cc5a9c47672cf1a6747bb073e8e74f7350/addons/stock_account/models/product.py#L60-L69 Now, the issue is that the `product_template` of the component belongs to "company1" so that the user is unauthorized to read the valuation method of the product category for "company1". opw-6216141 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274108 Forward-Port-Of: odoo/odoo#272429
This update fixes how the system recognizes URLs that point to local services, such as "http://localhost:8069". As a result, these links will now be handled consistently instead of being skipped, which improves testing and local setup workflows.
Original PR description
Before this commit, url like `http://localhost:8069` were ignored by the `urlRegexp` because it requires a Top-Level Domain. This commit makes the Top-Level Domain optional. Forward-Port-Of: odoo/odoo#274379
This fix prevents an error when changing a product’s Bill of Materials type in one company while related sales exist in another company. It ensures Odoo only blocks changes when the affected records belong to the same company, avoiding unnecessary interruptions for users working across companies.
Original PR description
### Steps to reproduce: - Have two companies: company1 and company2 - Create a producct P available in both company1 and company2 - with company1, create a kit bom for a product P - with company2,…
### Steps to reproduce: - Have two companies: company1 and company2 - Create a producct P available in both company1 and company2 - with company1, create a kit bom for a product P - with company2, create and confirm a sale order for 1 unit of P - with company1, change the bom type of P from kit to manufature #### > UserError: As long as there are some sale order lines that must be delivered/invoiced and are related to these bills of materials, you can not remove them. ### Cause of the issue: Changing the bom type from a kit (phantom type) to a non kit will launch a call of the `_ensure_bom_is_free` in order to ensure data integrity if the kit bom was used by a relevant sale order line: https://github.com/odoo/odoo/blob/f4c76be062bec47b68ee42505d7d42fed31ac0f2/addons/sale_mrp/models/mrp_bom.py#L15-L18 https://github.com/odoo/odoo/blob/f4c76be062bec47b68ee42505d7d42fed31ac0f2/addons/sale_mrp/models/mrp_bom.py#L24-L42 However, this check does not take the company of the bom into account and in the present flow, the company of the bom is different from the company of the supposedly problematic sol. opw-6290304 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273839 Forward-Port-Of: odoo/odoo#271119
When a new Indian company is created, the shared Half Up cash rounding is now duplicated for that company instead of being moved from the previous one. This prevents access errors on invoices and ensures each company keeps its own rounding setup.
Original PR description
### Issue: When creating a new Indian company, the `Half Up` cash rounding is reassigned to the new company instead of being duplicated Previous Indian companies lose access to it, causing errors…
### Issue: When creating a new Indian company, the `Half Up` cash rounding is reassigned to the new company instead of being duplicated Previous Indian companies lose access to it, causing errors when opening invoices that reference the cash rounding if the user doesn't have access to that company ### Cause: `cash_rounding_in_half_up` was defined as a `data` record with a fixed XML ID (`l10n_in.cash_rounding_in_half_up`) `_get_in_account_cash_rounding` referenced that XML ID directly and set `company_id` to the current company on each chart of accounts installation This reassigned the single shared record to the new company instead of creating a new one Moving the definition to the `@template` decorator without a module-prefixed XML ID lets the chart of accounts system create one record per company, as intended ### Steps to reproduce: - Install `l10n_in` and switch to `IN Company` - Check the Cash Rounding records grouped by company - Create a new Indian company - Enable both `IN Company` and the new company - Check the Cash Rounding records grouped by company again Before the fix, only the last created Indian company has the Cash Rounding record opw-6318857 Forward-Port-Of: odoo/odoo#272866
This fix ensures that when a cashier logs into Point of Sale using an employee account, the receipt sent by email shows the same cashier name as the in-store receipt. It prevents customers from seeing the connected user’s name instead of the actual employee who handled the sale.
Original PR description
Currently, when using the "login with employee" feature and sending the order receipt by mail, the cashier name is not the name of the employee using the pos. Steps to reproduce: ------------------- * Use the login with employee feature * Open the pos * Connect with an employee not linked to the current user * Make an order * Send the receipt to the customer by mail. > The receipt from the shop shows the cashier's name, the receipt sent by mail shows the connected user as the cashier opw-6291485
The Unit Cost History report now shows quantities using the product’s own unit of measure instead of the move’s unit. This fixes inflated quantities and added value amounts when materials are consumed in a different unit, giving users accurate costing information.
Original PR description
**Issue** The quantity displayed in the Unit Cost History report can be incorrect when the move UoM differs from the product UoM. **Steps to reproduce** - Create an AVCO product Comp tracked in tons…
**Issue** The quantity displayed in the Unit Cost History report can be incorrect when the move UoM differs from the product UoM. **Steps to reproduce** - Create an AVCO product Comp tracked in tons with a unit price of 100. - Create another product with a BoM consuming 100kg of Comp - Create, confirm and produce a MO for that product - Open the Unit Cost History for Comp -> Quantity is incorrect (100 instead of 0.1). As a consequence, the computed added value displayed in the report is also incorrect (10000 instead of 10). **Cause** The quantity and added value fields come from the `stock.avco.report` model, which is defined by this SQL view: https://github.com/odoo/odoo/blob/aef190dbff365f4fe5d92a2c41c35f92b66ce5fd/addons/stock_account/report/stock_avco_audit_report.py#L36-L39 The view uses the `quantity` field of `stock.move`: https://github.com/odoo/odoo/blob/aef190dbff365f4fe5d92a2c41c35f92b66ce5fd/addons/stock_account/report/stock_avco_audit_report.py#L48 without converting it in the right uom opw-6271229 Forward-Port-Of: odoo/odoo#269846
This update improves the speed of finding tasks in timesheets when the holidays extension is installed. It helps users get search results more quickly, making time entry and task lookup smoother.
Original PR description
This commit adds an index to speed up the task name_search in timesheets when project_timesheet_holidays is installed.
This change fixes the “Parallax to Bottom” intensity slider so users can choose custom values below the previous limit. It prevents the slider from snapping back to the minimum, making the website builder behave as expected.
Original PR description
`BuilderRange` supported inverted ranges (`props.min > props.max`) to keep the slider direction consistent across options, which was the case for the `Parallax to Bottom` (`min="-0.15" / max="-3"`) with `get min()`/`get max()` normalizing the bounds and `o_we_inverted_range` flipping the direction whenever `props.min > props.max` was detected. For the Bottom case, any value smaller than `-0.15` (e.g. `-1.5`) satisfied `value < props.min` and was clamped back to `-0.15`, making custom intensities impossible. Since this is the only inverted `BuilderRange` in the codebase, we restored the right order for the min/max, dropped the getters and replaced them with a prop to apply the `o_we_inverted_range` class in this scenario only. task-6058500 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#255252
A technical issue prevented users from previewing the '2Fa New Login' template. This was caused by an assertion that triggered when the preview environment lacked the necessary permissions. The fix replaces the assertion with a conditional check that returns placeholder data, allowing the preview to function correctly.
Original PR description
Issue: ---------------------------------------- Clicking "Preview" on the template "2Fa New Login" causes an error. Steps to reproduce: ---------------------------------------- - Search for the mail template "Settings: 2Fa New Login" - Click "Preview" - Error in terminal - From 17.0+ the error shows in UI - From saas-18.3+, a traceback occurs whe resetting the template Cause: ---------------------------------------- There is an assert the method `_get_totp_mail_code()` to ensure it's used during 2FA. But when passing by rendering this template in preview we aren't in sudo and the assert in `_get_totp_mail_code()` raises. Solution: ---------------------------------------- We replace the `assert` by a `if` which will return fake results. opw-6333887 Forward-Port-Of: odoo/odoo#273914 Forward-Port-Of: odoo/odoo#273125
This update ensures that webp images, like other image formats, are now subject to the 50MPx resolution limit when uploaded through the website editor. Previously, webp images could be uploaded regardless of size, leading to potential issues with website performance and design. This change corrects a bug in the image processing system.
Original PR description
Since 17.0, `webp` images can be uploaded at any resolution, whereas every other format is refused above IMAGE_MAX_RESOLUTION (50 Mpx) when the attachment is created on the server. Root cause…
Since 17.0, `webp` images can be uploaded at any resolution, whereas every other format is refused above IMAGE_MAX_RESOLUTION (50 Mpx) when the attachment is created on the server. Root cause =========== `ImageProcess` grouped webp together with empty sources and SVG and set `self.image = False`, returning before the `verify_resolution` check. As a result the resolution limit enforced for `png/jpeg/...` was never applied to `webp`. Fix === Split `webp` out of the skip branch: it is still not processed as before, but its resolution is now read from the RIFF header with `get_webp_size()` and checked against `IMAGE_MAX_RESOLUTION`, so oversized webp images are refused on upload like any other format. Steps to reproduce =================== 1. Edit any page with the website editor 2. Upload a `webp` image larger than 50 Mpx (e.g. 8000x8000) => The image is accepted, while a `png/jpeg` of the same size is refused task-4134430 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273570 Forward-Port-Of: odoo/odoo#273010
This update fixes a UI issue where refunds weren't accurately displaying the change amount. Previously, the system incorrectly showed change as a positive value. Now, refunds and overpayments are displayed correctly as negative amounts, ensuring accurate financial reporting and a better customer experience.
Original PR description
Steps to Reproduce ------------------------ - Install point of sale. - Do a order and pay more than the amount. Issue ------ - The change amount is displayed as a positive value on the UI. - Typically, amounts going out of the shop (like change given to the customer) should be shown as negative. Cause ------- - The change amount was not correctly represented in the UI. - Since the change flows in the opposite direction of the payment, it should be displayed as the negation of the original amount. FIX ----- - Updated the frontend to display the change amount with the correct (negative) sign. - No backend changes were required, as the correct value was already being handled during order synchronization Enterprise PR: https://github.com/odoo/enterprise/pull/112560 task: 6074620 Forward-Port-Of: odoo/odoo#263606 Forward-Port-Of: odoo/odoo#256776
This commit addresses a minor issue identified in a previously merged test related to the Italian VAT withholding functionality. The change ensures the test accurately reflects the current state of the code, preventing potential discrepancies in reporting. This is a routine maintenance update to maintain the quality and reliability of our Italian tax integration.
Original PR description
This commit just want to correct a test of a PR already merged. Original commit: 78ffb5a2e63401123e4506056493e52cf3e69953 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274262 Forward-Port-Of: odoo/odoo#274062
This update fixes an issue where purchase order receipt deadlines weren't updating correctly after quantities were set to zero. The fix ensures that cancelled stock moves no longer incorrectly influence the calculated deadline, providing accurate and reliable receipt scheduling for purchase orders. This improves the accuracy of delivery timelines.
Original PR description
Steps to reproduce the bug:
- Create a Purchase Order with 2 products and confirm it
- Note the receipt's deadline (= date_planned of both lines)
- Set the quantity of one PO line to 0
- Update the scheduled date (date_planned) of the purchase order
Problem:
the receipt deadline does not update.
The receipt kept the old deadline from the cancelled move. When a PO line qty is set to 0, `_merge_moves` cancels the corresponding stock move via `_action_cancel`. Then `_update_move_date_deadline` correctly skips cancelled moves (filtered by `state not in ('done', 'cancel')`), so the cancelled move retains its original `date_deadline`. However, `_compute_date_deadline` on `stock.picking` used
`move_ids.filtered('date_deadline')`, which not checks move state, so the stale deadline of the cancelled move was included in the min/max computation.
opw-6292600
Forward-Port-Of: odoo/odoo#271890
Forward-Port-Of: odoo/odoo#270985This update fixes a testing issue within the account_edi_ubl_cii module by using a realistic partial XML file for partner bank account retrieval tests. Previously, a generated XML was used, which wasn't representative of real data. This change ensures more accurate and reliable testing of the bank account retrieval process.
Original PR description
Move the partner retrieval bank account number test to the `test_ubl_import_bis3_invoice_be_retrieve_partner.py` file and use a partial XML instead of a generated XML. Forward-Port-Of: odoo/odoo#274158 Forward-Port-Of: odoo/odoo#269995
This update fixes an issue where scrap orders for products with multiple lots were only scrapping one lot at a time. The change ensures that the full intended quantity from a multi-lot product is correctly scrapped, resolving a discrepancy in inventory tracking. This was caused by a change in how the system handles quantity reservations during scrap order creation.
Original PR description
Currently, when a user creates and confirms a scrap order for a product that has multiple lots, only a quantity of 1 is being scrapped instead of the full intended quantity. ## Steps to replicate: *…
Currently, when a user creates and confirms a scrap order for a product that has multiple lots, only a quantity of 1 is being scrapped instead of the full intended quantity. ## Steps to replicate: * Install Inventory and enable Lots and Serial Numbers from settings * Create a product 'screw' tracked by lots. * Create two lots for the product with on hand quantity of 100 on each lot. * Create a scrap order > Set lot to second created lot > Set quantity to 50 * Save and confirm the scrap order. * Go to screw and check the on hand quantity ## Observed Behavior: Only a quantity of 1 from the lot has been scraped, which is incorrect. According to the scrap order, a total quantity of 50 should have been scraped. ## Root cause: This issue arises from how inverse methods are triggered when the form is saved. When saving, the `_set_quantity` method is executed first for the quantity field. This method calls `_set_quantity_done`, which in turn invokes `_set_quantity_done_prepare_vals` [1]. At this stage, there are no existing move lines. As a result, the initial loop in [1] is skipped. Because no move lines are present, the system proceeds to reserve quantities using `_get_reserve_quantity` [2]. Since no `lot_ids` have been set yet (because `_set_quantity` is executed before lot assignment), the reservation follows the warehouse’s default removal strategy, which is FIFO. Consequently, it selects quantities from Lot 1 first. These reserved quants are then used to prepare move line values [3]. The lot information is taken directly from the quant itself [4], resulting in move lines being created with Lot 1. **At this point, the system state is:** **Stock move:** | Field | Value | |--------|--------| | Lot IDs | 2 | | Quantity | 50 | **Stock move line:** | Field | Value | |--------|--------| | Lot ID | 1| | Quantity | 50 | Next, the inverse method for setting lots, `_set_lot_ids`, is triggered. Since the lot on the move (Lot 2) does not match the lot on the move line (Lot 1), the system schedules the existing move line for deletion (as shown in [5]). Additionally, because the move’s lot (Lot 2) is not present in the move lines, a new move line is created with at [6]: **Lot ID :** 2 **Quantity:** 1 <h3>Why didn’t this issue occur in earlier versions?</h3> In previous versions, scrapping was handled by a separate model (stock_scrap). Move lines and move values were only created when the scrap operation was confirmed. However, after this [commit](https://github.com/odoo/odoo/commit/1c7d80a10b5d7db1c4163166bf52b3f3c77044ba), the `stock_scrap` model was merged into the stock move model. Due to this change, inverse methods are now triggered directly when interacting with the scrap form view, leading to the behavior described above. [1]: https://github.com/odoo/odoo/blob/3a40c7a8e01d5b835db19b46bb45dfbeac7c16cd/addons/stock/models/stock_move.py#L2332-L2399 [2]: https://github.com/odoo/odoo/blob/3a40c7a8e01d5b835db19b46bb45dfbeac7c16cd/addons/stock/models/stock_move.py#L2388-L2398 [3]: https://github.com/odoo/odoo/blob/3a40c7a8e01d5b835db19b46bb45dfbeac7c16cd/addons/stock/models/stock_move.py#L2396 [4]: https://github.com/odoo/odoo/blob/3a40c7a8e01d5b835db19b46bb45dfbeac7c16cd/addons/stock/models/stock_move.py#L1755-L1764 [5]: https://github.com/odoo/odoo/blob/3a40c7a8e01d5b835db19b46bb45dfbeac7c16cd/addons/stock/models/stock_move.py#L618-L620 [6]: https://github.com/odoo/odoo/blob/3a40c7a8e01d5b835db19b46bb45dfbeac7c16cd/addons/stock/models/stock_move.py#L632-L641 ## Solution: By passing `lot_ids` in the context during scrap creation, the system can reserve quantities from the correct lots when setting quantities. This ensures that the lot assignment is consistent from the beginning. As a result, the `_set_lot_ids` logic executes correctly, avoiding unnecessary deletion of existing move lines that would otherwise occur due to mismatched lots between the move and its move lines. opw-6109494
This update resolves an issue where creating multiple applications with the same applicant information would trigger an error within the Talent Pools feature. The fix restricts the duplication of talent records, preventing the system from encountering a 'singleton' error. This ensures a smoother application process for users.
Original PR description
When multiple talent records share the same information, opening the Talent Pools smart button from a matching application will trigger a traceback. Steps to reproduce the error: - Install…
When multiple talent records share the same information, opening the Talent Pools smart button from a matching application will trigger a traceback. Steps to reproduce the error: - Install ``hr_recruitment`` module with demo data - Go to Recruitment > Applications > Talent Pools > Create a new pool - Go to Recruitment > Applications > All Applications > Create a new application with valid email > Click Add to Pool > Select the Talent Pool > Add to Pool - Duplicate the created talent record - Create another application with the same email > save > click Talent Pools Traceback: ```py ValueError: Expected singleton: hr.applicant(2, 1) ``` https://github.com/odoo/odoo/blob/d4e76a5663223a2a2c6e50d1701fabbdcaf32405/addons/hr_recruitment/models/hr_applicant.py#L857-L859 Here, the talent is searched using matching applicant information. When a matching talent has been duplicated, the search returns multiple records. Assigning a multi-records to the many2one field ``pool_applicant_id`` then raises a singleton error. Solution: Restrict the duplication of talent. sentry-7556261128 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273565 Forward-Port-Of: odoo/odoo#270827
Features or functions removed from Odoo
Due to Paymob unexpectedly ceasing operations in Pakistan, we've removed support for this payment provider within Odoo. This change ensures continued functionality and avoids disruptions for users who no longer rely on Paymob in that region.
Original PR description
Paymob stopped their operations in Pakistan unexpectedly. Domain was dropped so none of the APIs work for Pakistan. Therefore we are removing the support of Pakistan in the Paymob provider. See Also: https://github.com/odoo/documentation/pull/18768 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273935