Friday, July 4, 2025
20 changes · saas-18.4
Enhancements to existing features
This update improves how stock replenishment needs are calculated by processing orderpoint quantities in batches. It also corrects a purchasing-related issue so purchase orders are considered accurately without accidentally scanning unrelated records.
Original PR description
The method `orderpoint._compute_qty_order_computed` was batched in commit 17a2de9 then reverted in commit a58b995 because of a bug introduced when purchase_stock is installed. It should still be beneficial performance-wise to batch the calls to `orderpoint._quantity_in_progress` so this commit reintroduces the batching. The part that led to the issue was the override of `_quantity_in_progress` in the purchase_stock module. In this commit we fix the `_quantity_in_progress` method. Thanks to that, the test introduced in 606dc71 is passing even with the batched version of `_compute_qty_to_order_computed`. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#213154
Resolved issues and error corrections
Price list rules now update correctly when products or variants are changed, reducing pricing mistakes. Archived price lists are hidden from rule views, and price-related labels and inputs are clearer based on enabled settings.
Original PR description
--- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fixes cases where website-specific hidden elements could still appear because the system checked a shared template status instead of the current website's setting. Website editors can now more reliably show or hide menu and template options for each website.
Original PR description
Fixed cache pollution of _get_cached_template_info and added tests regarding the website editor, more specifically on enabling or disabling options related to views. Context: - Base: - the xmlid and…
Fixed cache pollution of _get_cached_template_info and added tests
regarding the website editor, more specifically on enabling or disabling
options related to views.
Context:
- Base:
- the xmlid and key of ir.ui.view are unique;
- the ir.ui.view are inherited if they are active, otherwise inheritance
is not applied;
- _get_cached_template_info(key) returns the cached record values.
- Website:
- the key of ir.ui.view are not unique; they can exist for different
websites and without a website;
- the ir.ui.view are inherited if they are active, otherwise inheritance
is not applied. If a specific inherited view exists (for the current
website), the default view (with same key) is not applied;
- for t-call, the specific view are used only if the view is active,
otherwise the default view is displayed;
- is_view_active(key) should return False if the view of the website in
question is inactive. If the default view is False, but the website
view is True, then the response should be True;
Issue:
`is_view_active` returns True if a view with this key is active, ignoring
the website-specific inactive view.
The issue was seen because the editor changes the display (active) of the
views by copying them with the website reference. So when we want to
change the menu, and hide it, the view is copied and set active=False.
Part of the menu was still visible because it uses a
`t-if="is_view_active(...)"`.
Issue introduced by: 97c2dd2ec569d34b044da6aa6f473277b48ada12This fix prevents users from being redirected to another website page after clicking Edit while the editor is still loading on a slow connection. It keeps the website builder focused on the intended page, avoiding a broken editing session and user confusion.
Original PR description
With a slow connection, it is possible to click on edit, then click on a menu link before the builder opens and be redirected. This should not be possible and was not the case before [1]. Steps to reproduce: - Set your network to "regular 3G" - Click on Edit - Click on another menu item => The iframe is redirected, then the builder sidebar opens but you can't edit the page. [1]: https://github.com/odoo/odoo/commit/9fe45e2b7ddbbfd0445ffe25a859e67a316d02b2 task-4367641
Website builder snippets now appear in the correct default language when editing multilingual websites, including after switching between websites. The related automated test has also been restored to help prevent this issue from returning.
Original PR description
\* = html_builder, website This PR re-enable the `test_snippet_translation` test that were broken and skipped after the DOM changes introduced by the new Website Builder and adapts it's tour selectors. (commit 2) It also fixes some translation related issues that were introduced by the new Website Builder. (see commit 1 and 3)
Sales orders created under a branch company now calculate unit prices correctly when product taxes belong to the parent company. This prevents incorrect displayed prices when fiscal positions convert price-included taxes to price-excluded B2B taxes.
Original PR description
Versions -------- - 17.0+ Steps ----- 1. Set up 10% price-included tax; 2. copy the tax to a B2B version that's price-excluded; 3. create a B2B fiscal position mapping the first tax to the second; 4.…
Versions -------- - 17.0+ Steps ----- 1. Set up 10% price-included tax; 2. copy the tax to a B2B version that's price-excluded; 3. create a B2B fiscal position mapping the first tax to the second; 4. create a $10 product using the first tax; 5. create a branch for the current company; 6. switch to the branch company; 7. set up a sale order with the fiscal position; 8. add the product to the order. Issue ----- While the line displays the correct B2B tax, the unit price displays $10, as if it was computed without any taxes, instead of a price-excluded tax. Cause ----- In the `_compute_price_unit` method, it filters out all tax records linked to the product that don't have the same company as the order line, so the parent company's tax does not get factored in. Solution -------- Rather than requiring strict equality between companies, also allow taxes that belong to a parent company of the line's company. opw-4853042 Forward-Port-Of: odoo/odoo#217012 Forward-Port-Of: odoo/odoo#216124
Link editing now handles links that contain images, buttons, or other formatted content without removing or breaking that content. This prevents issues in apps like Todo and Recruitment where editing a link could damage the email/template formatting or leave the edit popover stuck open.
Original PR description
reproduction: 18.0+18.1: 1. In Todo, insert an inline image, and create a link including the image and some text 2. click on the text part, click edit button, modify the label area and click apply 3.…
reproduction: 18.0+18.1: 1. In Todo, insert an inline image, and create a link including the image and some text 2. click on the text part, click edit button, modify the label area and click apply 3. the image is removed Test case 2: 1. go to Recruitment, and open an application and click "Send interview" 2. click on the link inside the template, change the url 3. apply, format of the button breaks 18.2: same flow with test case 2, click apply causing a traceback 18.3: same flow with test case 2, click on the link, do nothing and click away, the popover not close Fix: a partial back port of https://github.com/odoo-dev/odoo/pull/4633 The idea is that when the link doesn't only contain text, we don't show the label input field nor apply the label to the link. Because the label field extracts/display the text content of the link element, the field doesn't support html fragment, applying the label on a link including another element inside will break it. on 18.4+, we only rename the variable from isLabelHidden to showLabel task-4881878 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#217226 Forward-Port-Of: odoo/odoo#215023
This fixes an inventory issue where reducing a sales order quantity could create an extra incorrect delivery transfer when a route uses its own destination location. The change ensures stock adjustments use the intended route destination, keeping warehouse movements accurate and avoiding confusing duplicate pickings.
Original PR description
Steps to reproduce: - Install Sales and Stock - Activate the multi-step routes setting - Go to a Delivery route in the warehouse - Change the `location_dest_id` of the operation type set on the rule…
Steps to reproduce: - Install Sales and Stock - Activate the multi-step routes setting - Go to a Delivery route in the warehouse - Change the `location_dest_id` of the operation type set on the rule - Enable the "Location Dest. Taken from Rule" checkbox - Ensure `rule.location_dest_id` and `operation_type.location_dest_id` are different - Create a Sales Order (SO) for a product with quantity = 5 and confirm - Change the SO line quantity to 3 and save Issue: A second picking is created with a move taking the product from `rule.operation_type.location_dest_id -> rule.operation_type. location_src_id` with quantity = -2. This happens because the decrease in the SO quantity triggers a negative move, and this move is not merged with the existing positive move. Instead, a new move is created in the opposite direction. In `_merge_moves`: https://github.com/odoo/odoo/blob/3c4275fb00255e519f01bf5547eff1db3a59d4b5/addons/stock/models/stock_move.py#L1191-L1193 It checks if the negative move has similar characteristics to the existing positive moves. However, the `neg_key(neg_move)` differs in `location_dest_id`, so the merge fails. This happens because the negative move does **not** read the `location_dest_id` from the rule — unlike the procurement, which **does** use the rule and therefore creates positive moves with the correct destination. When the negative move is created with the procurement, it initially has the correct `location_dest_id`. But then: https://github.com/odoo/odoo/blob/b984c72df398c4fe942d8894442e4e893ca0660e/addons/stock/models/stock_move.py#L1191 triggers `_compute_location_dest_id`, which doesn't consider the `rule.location_dest_id` and defaults to `operation_type. location_dest_id`, causing the merge to fail due to mismatched destination_locations. The positive move has read the correct value, because when it was assigned to a picking, the picking has the correct destination from the procurement. But for the neg_move it has picking None so it maps to the operation_type without consdiering the location from rule checkbox. opw-4793171 Forward-Port-Of: odoo/odoo#212355
This fixes an issue where manually adjusted extra hours on an employee attendance could be overwritten when a new attendance was created. The change helps preserve user-entered overtime values in automatic approval setups, reducing payroll and attendance corrections.
Original PR description
**Steps to reproduce** - Set "Extra Hours Validation" to "Automatically approved" - Create an attendance for an employee - Change the "Extra Hours" to a different value - Create another attendance…
**Steps to reproduce** - Set "Extra Hours Validation" to "Automatically approved" - Create an attendance for an employee - Change the "Extra Hours" to a different value - Create another attendance for this employee (not necessarily on the same day) - See that the "Extra hours" of the previous attendance has been recomputed, resetting the value entered by the user. **Cause** When creating an attendance for an employee, we recompute the `validated_overtime_hours` for the other attendances of this employee https://github.com/odoo/odoo/blob/cac96f5d3c391ea0d52da2e3433e7eabe07e8fb0/addons/hr_attendance/models/hr_attendance.py#L426 In case of attendances with no validation, this field is synced with the `overtime_hours` https://github.com/odoo/odoo/blob/cac96f5d3c391ea0d52da2e3433e7eabe07e8fb0/addons/hr_attendance/models/hr_attendance.py#L156 **Solution** We may still want to recompute the `validated_overtime_hours` of automatically approved attendances, since it is their default state, unlike manually approved attendances. If the `validated_overtime_hours` field is different from `overtime_hours`, it means it has been modified. In that case, we avoid recomputing it. This doesn't guarantee a manually set value will never be overriden by a change in its dependencies, but it reduces the likelihood. opw-4639230 Forward-Port-Of: odoo/odoo#207806
This fix restores reliable resizing of grid-based content boundaries in the website editor. Business users editing pages can now adjust elements such as the Pills snippet as expected, reducing layout frustration and editing interruptions.
Original PR description
Before this commit, grid resizing wasn't working properly, because of the pointer up event not firing. To reproduce the issue: - open website, start editing - drop the "pills" snippet - click on text and try to resize its 'boundaries' => It's not working as expected This commit follows the [html_builder refactoring] [html_builder refactoring]: odoo/odoo@9fe45e2b7ddb Related to task-4367641
Payments using an existing third-party check now automatically use the check's original currency, avoiding incorrect currency conversions. The system also blocks combining checks in different currencies, reducing payment errors for Latin American check workflows.
Original PR description
**Steps to reproduce:** - Install accountant, l10n_ar and l10n_latam_check - Switch to an Argentinian company (e.g. (AR) Responsable Inscripto) - Make sure that USD currency has a rate different than…
**Steps to reproduce:**
- Install accountant, l10n_ar and l10n_latam_check
- Switch to an Argentinian company (e.g. (AR) Responsable Inscripto)
- Make sure that USD currency has a rate different than 1
- Create a journal:
* Journal Name: Checks journal
* Type: Cash
- Save the journal
=> a Cash Account should be automatically created
- In "Incoming Payments" tab of the journal, set:
* "New Third Party Checks" with the Cash Account
* "Existing Third Party Checks" with the Cash Account
- In "Outgoing Payments" tab of the journal, set:
* "Existing Third Party Checks" with the Cash Account
- Create an invoice:
* Customer: [an Argentinian customer] (e.g. ADHOC SA)
* Currency: ARS
* Invoice Lines:
- Quantity: 1
- Price: 150000.00
- Taxes: VAT 21%
- Confirm the invoice
- Pay the invoice:
* Journal: [the created Checks journal]
* Currency: ARS
* Checks: [add a line with the amount of the invoice]
- Create a bill:
* Vendor: [an Argentinian customer] (e.g. ADHOC SA)
* Currency: USD
* Invoice Lines:
- Quantity: 1
- Price: 500.00
- Taxes: VAT 21%
- Pay the bill:
* Journal: [the created Checks journal]
* Payment Method: Existing Third Party Checks
* Checks: [add a line and select the check used to pay the invoice]
**Issue:**
When the check (from the invoice) is selected to pay the bill, the original amount (in ARS) is used but the currency stays in USD, which is not correct.
If the currency is changed to ARS, the currency rate is applied on the amount that is already the amount in ARS, which generates a higher incorrect amount.
**Solution:**
Use the currency set on the existing check by default.
Also prevent adding several checks with different currencies.
opw-4741607
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#215435This fixes an issue in Point of Sale where entering extra digits after using quick amount buttons could produce the wrong payment amount. Cashiers can now reliably type payment amounts, reducing checkout errors and manual corrections.
Original PR description
Steps to reproduce: =================== - Add a product to the orderline from the product screen - Click payment - Select any payment method - Enter the amount manually - Press `+20`, then press `2`, OR press `+20`, then press `6` Issue: ====== - In the case of `+20` and `2`, the expected result is `202`, but we get `20` - In the case of `+20` and `6`, the expected result is `206`, but we get `20.01` Cause: ====== - `formatCurrency` is used for the buffer, but the buffer should not depend on the currency Fix: ==== - Remove the usage of `formatCurrency` and treat the buffer as a string Task: 4850543 Forward-Port-Of: odoo/odoo#217108 Forward-Port-Of: odoo/odoo#213294
The live chat widget page now adapts properly to smaller mobile screens. This prevents text and layout from overflowing, making it easier for visitors to use chat from their phones.
Original PR description
**Before this PR:** the livechat widget page was not responsive on mobile devices. This PR fixes the issue by adding the missing meta tag and adjusting font sizing and word wrapping to prevent content overflow on small screens. task-3499603 Forward-Port-Of: odoo/odoo#217127
Fixes several subscription pricing issues so customers see the right recurring and one-time prices, including pricelist visibility, plan availability, and discounts. It also improves product duplication behavior by copying valid pricing rules and ignoring obsolete inactive-product rules, reducing errors for sales teams.
Fixed an issue where some Winbooks journals were skipped during import when their codes were longer than the allowed length and shared the same starting characters. The import now assigns clear temporary codes to those duplicate cases, helping Belgian accounting migrations bring in all journals reliably.
Original PR description
**Steps to reproduce:** - Install accountant, l10n_be and account_winbooks_import - Switch to a Belgian company (e.g. BE Company CoA) - Go to "Accounting / Configuration / Settings" - Click on…
**Steps to reproduce:** - Install accountant, l10n_be and account_winbooks_import - Switch to a Belgian company (e.g. BE Company CoA) - Go to "Accounting / Configuration / Settings" - Click on "Import (for full history)" in "Accounting Import" section - Click on "Import WBK" in "Winbooks" section - Upload a Winbooks file containing several journals having their "DBKID" value longer than 5 characters with the 5 first characters being identical (e.g. "SALES001", "SALES002",...) - Import **Issue:** Some journals are not imported. **Cause:** The code of a journal is limited to 5 characters and is unique per company. When a code is longer than 5 characters, only the 5 first characters are kept. In this case, several journals to create have the same 5 first characters. Therefore, only one of them is created. **Solution:** If the code of a journal to create has the same first 5 characters of a journal that has already been created (and the same last 5 characters), we use a generic code formatted with a starting "*" char followed by a number that is incremented. This format allows to quickly find it if we want to change its value once imported. This solution is limited to 9999 journals that have a code that can starts with the same 5 characters than another journal, but it should be more than enough. opw-4812655 Forward-Port-Of: odoo/enterprise#86068
This fix ensures the invoice sending time is saved before contacting the Mexican e-invoicing provider. If a connection drops during sending, Odoo can reuse the same timestamp when retrying, reducing duplicate CFDIs with slightly different dates.
Original PR description
### Background In https://github.com/odoo/enterprise/pull/85026 we changed the behaviour of `l10n_mx_edi_post_time` so that it gets set during the CFDI sending process, rather than when the invoice…
### Background In https://github.com/odoo/enterprise/pull/85026 we changed the behaviour of `l10n_mx_edi_post_time` so that it gets set during the CFDI sending process, rather than when the invoice is posted. This was needed to ensure that the post time both reflects the sending time and is re-used if the invoice needs to be re-sent. ### Bug description Since then, several Mexican customers have reported that some CFDIs are sent duplicated, with a difference of a few seconds in the CFDI's Fecha. ### Analysis A disconnection might occur during sending of the CFDI. In that case, the PAC will process the CFDI, but in Odoo the transaction will be rolled back, and the `l10n_mx_edi_post_time` will be lost. When Odoo re-sends the CFDI, it will take a new `l10n_mx_edi_post_time`. ### Solution Commit before performing the API call so that the `l10n_mx_edi_post_time` gets committed to DB. opw-4780096 Forward-Port-Of: odoo/enterprise#89263 Forward-Port-Of: odoo/enterprise#89117
Belgian payroll reports now calculate worker counts much faster, reducing a slow operation from about 50 seconds to under a second on odoo.com. This improves responsiveness for payroll teams and reduces waiting time when processing Belgian HR payroll data.
Original PR description
From 50 to 0.4 seconds on odoo.com
The UAE payroll rules now calculate end-of-service compensation in line with the official government calculator. Employees receive the 30-day compensation rate only after completing the sixth year, improving payroll accuracy and compliance.
Original PR description
- to algin with UAE goverment eos calculator, salary rule is update to concider full 30 compensation after completing the 6th year not the 5th. Task: 4756963 Forward-Port-Of: odoo/enterprise#89306 Forward-Port-Of: odoo/enterprise#84752
This fix prevents payslip creation from failing when a Belgian employee has a work entry spanning an unusually long period, such as a full month. Payroll teams can now generate the affected payslips without encountering the error.
Original PR description
There is a bug in the module that made the creation of payslip triggers an error. Steps to reproduce it :
1) Use a Belgian company and an employee with a contract;
2) Create a work entry for a whole month (from 05/01/2025 09:00:00 to 06/01/2025 17:00:00 for example);
3) Try to create a payslip for this employee.
Error :
File "/data/build/enterprise/l10n_be_hr_payroll/models/hr_contract.py", line 517, in _get_work_hours_split_half
work_data[('half', work_entry.work_entry_type_id.id)] += dt.days * 24 + dt.seconds / 3600 # Number of hours
TypeError: 'float' object is not iterable
[opw-4752109](www.odoo.com/odoo/project/49/tasks/4752109)
Forward-Port-Of: odoo/enterprise#88445
Forward-Port-Of: odoo/enterprise#84810Payslip company selection is now locked to the company derived from the employee, preventing mismatched company data in payroll batches. This avoids errors when creating draft accounting entries for batches containing payslips from multiple companies and provides a clearer validation message for older affected records.
Original PR description
Currently a traceback is occurring when the user tries to create a Draft Entry, in the batch that contains payslips of multiple companies. **To reproduce this issue:** 1) Install hr_payroll_account…
Currently a traceback is occurring when the user tries to create a Draft Entry, in the batch that contains payslips of multiple companies. **To reproduce this issue:** 1) Install hr_payroll_account and switch to multi-company environment 2) Create two employees with two running contracts respectively 3) Now create a Batch record from payroll/payslips/batches 4) Create two playslips with different companies with the created batch 5) Compute both the payslips and open the batch 6) Now, try to click on the Create Draft Entry **Error:** A traceback will occur. ``` ValueError: Expected singleton: res.company(1, 2) ``` **Cause:** When the user created multiple payslips with multiple companies containing the same batch and tries to create a Draft Entry, we filtered out the payslips based on the payslip state, and try to change the state to Done using the action_payslip_done method. https://github.com/odoo/enterprise/blob/1e5d7155466f80942f0b8fe2df7fdfb86cae7417/hr_payroll/models/hr_payslip_run.py#L70 So the self will contain multiple payslip recordsets with different company in each payslip. This leads to the above traceback when accessing company_id from self https://github.com/odoo/enterprise/blob/1e5d7155466f80942f0b8fe2df7fdfb86cae7417/hr_payroll_account/models/hr_payslip.py#L61 **Solution:** In payslips, the company_id field should be in readonly state, since the value of the company_id will computed from the employee_id which is a required field. Also raised a validation Error for the previously created record to handle the traceback. Related Upgrade PR:- https://github.com/odoo/upgrade/pull/7763 opw-4797089 Forward-Port-Of: odoo/enterprise#88307 Forward-Port-Of: odoo/enterprise#86628