Daily updates from Odoo
Navigate
Branch
Monday, November 10, 2025
128 changes
18 changes
Enhancements to existing features
This change makes checking bank statements for errors significantly faster. It reduces the database work needed for this task, which helps the system respond more quickly and lowers load on the database.
Original PR description
Description ----------- Avoid self-join of `account_bank_statement` that is done with a `Nested Loop` due to the `LATERAL`. Even if correlated, it requires two separate accesses to its index. Replaces it with a window function + `LAG` partitioned by the `journal_id`. This leads to a simpler plan (lower cost) and working in-memory instead of accessing disk pages (lower IO contention). Benchmark --------- On a database with 46k `account_bank_statement`, calling `_get_invalid_statement_ids` for all statements took: | [Before](https://explain.dalibo.com/plan/7605a4ddc42afbcf) | [After](https://explain.dalibo.com/plan/88d6ac1gee37aha3) | Speed-up | |--------|-------|----------| | 146ms | 72ms | 2x | --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#232980
Resolved issues and error corrections
This change prevents the website editor from getting stuck when a parallax background uses zoom effects while being edited. It improves the editing experience by keeping the page responsive and avoiding the loading spinner interruption.
Original PR description
Steps to reproduce: 1. Open website in edit mode. 2. Drop a large snippet (e.g., s_company_team_detail). 3. Add a parallax snippet below it. 4. Set the parallax scroll effect to `Zoom in` or `Zoom out`. 5. Scroll to the top of the page while keeping the parallax snippet selected. Current behavior: - The page scrolls slightly and a loading spinner appears. - Nothing happens until the user interacts. - Clicking cancels the repositioning. - Scrolling resumes the repositioning (sometimes with a delay). Root cause: The transform applied by the zoom scroll effects conflicts with the editor’s overlay repositioning, leaving the editor stuck in a loading state. Fix: Temporarily disable the transform applied by the Zoom in and Zoom out scroll effects when in edit mode. task-4925787
Channel mentions are now restored correctly when a user edits a message using the ArrowUp shortcut. This makes editing behave the same way as using the Edit action, helping prevent mentions from being lost.
Original PR description
**Description of the issue this PR addresses:** ------------------------------------------------ When editing a message via the ArrowUp shortcut, any previously mentioned channels (e.g., `#general`)…
**Description of the issue this PR addresses:** ------------------------------------------------ When editing a message via the ArrowUp shortcut, any previously mentioned channels (e.g., `#general`) were not restored in the composer. This happened because the logic to restore mentions was only applied in the `onClick()` handler of the Edit message action. **Current behavior before PR:** --------------------------------- - Editing a message using ArrowUp does not restore mentioned channels - Editing via the Edit message action still works correctly **Desired behavior after PR is merged:** ----------------------------------------- - Mentioned channels are restored when entering edit mode via ArrowUp - Behavior is consistent with editing through the Edit message action - No mentions are lost in any edit scenario **Important: This PR should only be merged for versions saas-18.2, saas-18.3, and saas-18.4.** **Backport of https://github.com/odoo/odoo/pull/229546/commits/5878e398615596adcf09eef8acbbe5aa739918f3** **Task:** 5133698 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#234995 Forward-Port-Of: odoo/odoo#231192
This update corrects two issues in DHL shipping requests so labels and export declarations can be processed successfully. It fixes a misspelled customer reference field and adjusts the shipment date/time format to match DHL’s requirements, preventing avoidable delivery errors.
Original PR description
Currently, when creating a DHL shipment with an export declaration that includes a customer reference, there is a misspelling of the field 'recipientReference' as 'recepientReference'. This causes…
Currently, when creating a DHL shipment with an export declaration that includes a customer reference, there is a misspelling of the field 'recipientReference' as 'recepientReference'. This causes validation errors when communicating with the DHL API. In addition, the datetime format used for the planned shipping date and time does not conform to the expected format specified by DHL. Steps to reproduce spelling issue: 1. Create a Sales Order with a customer reference and a deliverable product. 2. Validate the SO. 3. Go to the delivery, select DHL as carrier, and confirm. → Error: Validation error #/content/exportDeclaration: extraneous key [recepientReference] is not permitted. Steps to reproduce datetime issue: 1. Create a delivery using the DHL carrier. 2. Confirm the delivery. 3. Return the delivery. 4. Click "Print Return Label". → Error: Bad request #/plannedShippingDateAndTime is not well formatted (expected format: '2010-02-11T17:10:09 GMT+01:00'). Official DHL documentation: https://developer.dhl.com/sites/default/files/2025-11/dpdhl-express-api-3.1.1_swagger.yaml opw-5024363 Forward-Port-Of: odoo/enterprise#98981
This change fixes a visual issue where the breadcrumb label could briefly show the wrong name or flicker when moving between livechat sessions. It improves the user experience by keeping the session title consistent and readable during navigation.
Original PR description
Before this PR, The breadcrumbs flickered when navigating between livechat sessions. This occurred because the `FormController`…
Before this PR,
The breadcrumbs flickered when navigating between livechat sessions.
This occurred because the `FormController` ([@web/views/form/form_controller](https://github.com/odoo/odoo/blob/saas-18.3/addons/mail/static/src/core/web/discuss_patch.js#L16-L23))
updated the breadcrumb title inside the `onRendered` hook and set it to
`this.model.root.data.display_name` which is `undefined`, the `Discuss` component
also updated the breadcrumb title in a `useEffect` hook. ([@mail/code/web/discuss_patch.js](https://github.com/odoo/odoo/blob/saas-18.3/addons/mail/static/src/core/web/discuss_patch.js#L16-L23))
The two updates conflicted: the onRendered hook first set the title to
“Unnamed,” and then the useEffect hook replaced it with the correct title,
causing a brief flicker. Additionally, when navigating to another session with
the same thread.displayName, the useEffect hook did not trigger (since its
dependency did not change), but onRendered still ran, causing the breadcrumb
to remain “Unnamed”.
This PR fixes the issue by introducing a `LivechatFormController` which
updates the breadcrumbs when channel is fetched in store.
task-4671251
Before:

After:

task-4671251
Forward-Port-Of: odoo/odoo#233167This change fixes an error that appeared when users tried to upload a non-PDF file in the Sign app while debug mode was enabled. Instead of showing a traceback, the app now displays a clear message telling users the file type is not supported.
Original PR description
Version: - saas-18.3 Steps to reproduce: - Enable debug mode. - Try uploading a non-PDF file in the Sign app. Before: - Uploading a non-PDF file in debug mode caused a traceback error. - The TemplateAlertDialog component tried to use a message prop that wasn’t defined. After: - Replaced the use of the undefined message prop with the correct body prop to display the error message. Impact: - Fixes the traceback error in debug mode. - Shows a clear and user-friendly error message when uploading unsupported file types. task-4828439 Forward-Port-Of: odoo/enterprise#89081
This update prevents Shiprocket from failing when tax mapping is used but the expected GST tax labels are not available. It also makes the related test more reliable by explicitly using a 15% tax, so the check behaves consistently across different company setups.
Original PR description
Some other test adds a fiscal position with tax mapping. This creates 2 problems 1. The new taxes have a tag, which means we evaluate the right hand of…
Some other test adds a fiscal position with tax mapping. This creates 2 problems
1. The new taxes have a tag, which means we evaluate the right hand of
https://github.com/odoo/enterprise/blob/8d3fe30c627eada1186c15480876fb2e8f7ddb59/delivery_shiprocket/models/shiprocket_request.py#L239
However, since l10n_in is not installed,
`tax.env.ref(f"l10n_in.tax_tag_{gst}gst", False)`
does not return anything (False is not a fallback)
https://github.com/odoo/odoo/blob/1e96a3d127e8f521d3027f7110026ae84e11ed5e/odoo/api.py#L588
So we end up looking for `None` in `tax_tag_ids`, which leads us to compare the `_name` properties, see
https://github.com/odoo/odoo/blob/1e96a3d127e8f521d3027f7110026ae84e11ed5e/odoo/models.py#L6545-L6558
2. The test added in 4d5df93 was assuming the default company 15% tax, which was not always true
Solution
-----
1. Provide a fallback for the `ref` lookup
2. Force a 15% tax in the test
-----
runbot-232692
Forward-Port-Of: odoo/enterprise#99027
Forward-Port-Of: odoo/enterprise#97998Quality checks created from receipts now use the correct company instead of the currently active one. This prevents errors in multi-company setups when a receipt is confirmed from a different company than the one linked to the control point.
Original PR description
When creating quality checks per quantity, a multi-company error occurs if the active company differs from the one defined on the control point. Steps to reproduce: - Create a Quality Control Point for Company B and Product Table for the receipt operation with a per-quantity control. - Create a receipt in Company B for this product but leave it in draft. - Switch to Company A and try to confirm → error. Root cause: The company_id was not set when creating the quality check, causing it to default to `env.company` (A) instead of the stock move line’s company (B). opw-86993 Forward-Port-Of: odoo/enterprise#99024 Forward-Port-Of: odoo/enterprise#98655
This update prevents an access error that could occur when opening the Documents app after a company was archived. It ensures users only see folders they are allowed to access, improving reliability when managing documents across companies.
Original PR description
**Steps to reproduce:** - Add some folders - Create a new company - Assign some folders to the new company - Archive the company - Click on Documents app - AccessError is raised when opening it…
**Steps to reproduce:** - Add some folders - Create a new company - Assign some folders to the new company - Archive the company - Click on Documents app - AccessError is raised when opening it **Issue:** The issue seems to be related to caching issue on the field `type` when fetching the documents with `search_panel_select_range` and going through `_compute_display_name`: `folders = accessible_records.filtered(lambda d: d.type == 'folder')` This error was quite inconsistent and might be related to the cache missing some prefetched data on a record it shouldn't have been able to read. There is a need to ensure only the folders available to the user are able to be fetched. **Fix:** Added the `type` field in the `search_panel_fields` but this might not be needed if the issue comes from elsewhere. For now the issue was mitigated by explicitly checking for the user companies in the domain of the searchs, but it needs to be checked as this behavior might break other flows. opw-4931278 Forward-Port-Of: odoo/enterprise#99043 Forward-Port-Of: odoo/enterprise#96817
Products with a single non-variant option now correctly reuse the same cart line instead of creating a new one each time they are added. This prevents duplicate entries in the shopping cart and keeps the checkout experience consistent for customers.
Original PR description
Versions -------- - 18.0+ Steps ----- 1. Have a product attribute with variant creation set to never; 2. have product using only this attribute, with only a single value; 3. open website editor on…
Versions -------- - 18.0+ Steps ----- 1. Have a product attribute with variant creation set to never; 2. have product using only this attribute, with only a single value; 3. open website editor on /shop; 4. enable add-to-cart button & save; 5. use button on the aforementioned product at least twice. Issue ----- Each time the product gets added, a new line is created. Cause ----- Because there's only a single value, the product configurator doesn't pop up by default when adding the product to the cart. Without the configurator pop-up, the `_cart_update` method doesn't receive any `no_variant_attribute_value_ids`, which are used find a matching line if the product template has any `no_variant` attribute. Solution -------- Instead of checking `product.product_tmpl._has_no_variant_attributes()`, to see if we should attempt to match `no_variant_attribute_value_ids`, check if the added product has any `no_variant` attributes that have more than one value or are optional (multi-checkbox). If not, a `no_variant` product behaves the same as a single-variant product. opw-5093175 opw-5137351 Forward-Port-Of: odoo/odoo#234958 Forward-Port-Of: odoo/odoo#233452
Amazon shipment updates now include the carrier code required in some countries, making delivery notifications more reliable. If the carrier cannot be matched exactly, the system sends a safe fallback so Amazon can still use the carrier name.
Original PR description
The `POST_ORDER_FULFILLMENT_DATA` feed that is used to push order delivery info to Amazon should follow the `OrderFulfillment` schema (see https://images-na.ssl-images-amazon.com/images/G/01/rainier/help/xsd/release_4_1/OrderFulfillment.xsd), but it was missing the `CarrierCode` element, which is required in some countries. This commit adds the missing element to the payload, with the formatted carrier name as a value. If the carrier name cannot be matched, "Other" is used as a fallback to signal Amazon that they should rely on the `CarrierName` instead. Forward-Port-Of: odoo/enterprise#99026
This fix allows sales orders created in a branch company to use payment providers set up on the parent company. It prevents customers from seeing a “No compatible payment providers found” message when paying online from a branch.
Original PR description
Versions -------- - 17.0+ Steps ----- 1. Have a published payment provider; 2. create a branch company; 3. create a sales order in branch company; 4. enable online payment for sales order; 5. open sales order in portal view; 6. attempt to pay. Issue ----- No compatible payment providers found. Cause ----- The `payment.provider._check_company_domain` is set to the default exact match, so when it's used in `_get_compatible_payment_providers`, it's unable to find any providers for the branch company. Solution -------- Set `_check_company_domain` to `check_company_domain_parent_of`. opw-5214269 Forward-Port-Of: odoo/odoo#234821 Forward-Port-Of: odoo/odoo#234763
This update restores menu mode in the self-ordering flow so customers can browse and order as expected. It improves the reliability of the ordering experience and prevents interruptions at checkout.
Original PR description
Menu mode was broken in self ordering. This commit fix it. Forward-Port-Of: odoo/odoo#234460 Forward-Port-Of: odoo/odoo#232503
Grouping records by a property tags field now works correctly in list views, even when users search within the grouped results. This prevents an error that could interrupt normal CRM usage and keeps grouped views stable.
Original PR description
Step to reproduce: - open crm and add a property tags field in a lead - add that tags in few leads - go to list view and group by that property tags field - search for a lead (keep groupby as it is)…
Step to reproduce:
- open crm and add a property tags field in a lead
- add that tags in few leads
- go to list view and group by that property tags field
- search for a lead (keep groupby as it is)
Observation:
- we receive a traceback
```
File "/home/odoo/odoo/codebase/odoo/saas-18.4/addons/web/models/models.py", line 396, in web_read_group
self._open_groups(
File "/home/odoo/odoo/codebase/odoo/saas-18.4/addons/web/models/models.py", line 537, in _open_groups
info_opening['value']: info_opening
TypeError: unhashable type: 'list'
```
Cause:
- `formatter_property_tags` returns a list in case of tags field.
https://github.com/odoo/odoo/blob/5186fd202373a67f56688c234fcde15cc1997721/addons/web/models/models.py#L1176
- these values are used as a key for dict in `_open_groups`, hence only hashable values are allowed; list is not hashable
https://github.com/odoo/odoo/blob/5186fd202373a67f56688c234fcde15cc1997721/addons/web/models/models.py#L536-L539
Fix:
- cast the list to tuple
opw-5188961
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prThis fix allows duplicate payroll slips to be canceled even when they share the same work entries. The system now only resets work entries to draft when they belong to the payslip being canceled, avoiding unintended side effects on other slips.
Original PR description
previous behavior: - Cancelling duplicate payslips wasn't possible because they had the same work entries linked current behavior: - Allows to cancel a duplicate payslip without affecting the linked work entries - Work entries are only set to draft when they are linked to one payslip that is being cancelled - added `test_duplicate_payslips_cancellation` task-id: 5075882
This change corrects a failing automated test in the manufacturing accounting area after a previous update to how duration is calculated. It helps keep the test suite reliable so future changes can be validated with confidence.
Original PR description
### Issue: This is caused by changing the duration inverse in #233777. ### Cause: Before #233777, in duration inverse, only sum of `time_ids` was taken into account to calculate the `duration`. After that PR, `time_ids` with `get_working_duration` are also taken into account which cause this test fail. runbot-233742
This update corrects how tax report returns are generated when a country has multiple report types. It prevents duplicate or incorrect closing entries and ensures some reports move to a review-and-submit flow when a closing entry is not needed, improving the accuracy of tax reporting.
Original PR description
It's possible for different tax reports to exist in the same country, each with its own return type. However, this is an issue when they aren't configured to generate closing entries with distinct contents, since each of them will then repeat the content of the other. To fix this, when it's legitimate to make multiple closing entries, we make sure the closing entry only considers the tax move lines linked to the report's tax tags. If multiple reports must generate the same closing entry (typically because one of them is a simplified version of the other), we disable the generation of the return for one of them. Some reports also didn't need to generate a closing entry and were switched to a 'review_submit' state. task-5123564 Forward-Port-Of: odoo/enterprise#98158
This update adjusts Odoo’s email sending setup to work correctly on newer Debian Trixie systems. It prevents warning messages and connection issues when testing or using the built-in mail server, helping email features remain reliable across environments.
Original PR description
Forward-Port-Of: odoo/odoo#234020 Forward-Port-Of: odoo/odoo#232699
14 changes
Enhancements to existing features
This change speeds up the check that finds invalid bank statements. It reduces database work, which makes the validation run about twice as fast and lowers load on the system.
Original PR description
Description ----------- Avoid self-join of `account_bank_statement` that is done with a `Nested Loop` due to the `LATERAL`. Even if correlated, it requires two separate accesses to its index. Replaces it with a window function + `LAG` partitioned by the `journal_id`. This leads to a simpler plan (lower cost) and working in-memory instead of accessing disk pages (lower IO contention). Benchmark --------- On a database with 46k `account_bank_statement`, calling `_get_invalid_statement_ids` for all statements took: | [Before](https://explain.dalibo.com/plan/7605a4ddc42afbcf) | [After](https://explain.dalibo.com/plan/88d6ac1gee37aha3) | Speed-up | |--------|-------|----------| | 146ms | 72ms | 2x | --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#232980
Resolved issues and error corrections
This update corrects two issues in DHL shipment requests: a misspelled customer reference field and an incorrect date/time format. As a result, DHL labels and return labels should now be created more reliably without avoidable validation errors.
Original PR description
Currently, when creating a DHL shipment with an export declaration that includes a customer reference, there is a misspelling of the field 'recipientReference' as 'recepientReference'. This causes…
Currently, when creating a DHL shipment with an export declaration that includes a customer reference, there is a misspelling of the field 'recipientReference' as 'recepientReference'. This causes validation errors when communicating with the DHL API. In addition, the datetime format used for the planned shipping date and time does not conform to the expected format specified by DHL. Steps to reproduce spelling issue: 1. Create a Sales Order with a customer reference and a deliverable product. 2. Validate the SO. 3. Go to the delivery, select DHL as carrier, and confirm. → Error: Validation error #/content/exportDeclaration: extraneous key [recepientReference] is not permitted. Steps to reproduce datetime issue: 1. Create a delivery using the DHL carrier. 2. Confirm the delivery. 3. Return the delivery. 4. Click "Print Return Label". → Error: Bad request #/plannedShippingDateAndTime is not well formatted (expected format: '2010-02-11T17:10:09 GMT+01:00'). Official DHL documentation: https://developer.dhl.com/sites/default/files/2025-11/dpdhl-express-api-3.1.1_swagger.yaml opw-5024363 Forward-Port-Of: odoo/enterprise#98981
Branch companies can now use payment providers set up at the parent company level when customers pay online from a sales order. This prevents checkout from failing with no compatible providers found and makes online payment work more smoothly across company structures.
Original PR description
Versions -------- - 17.0+ Steps ----- 1. Have a published payment provider; 2. create a branch company; 3. create a sales order in branch company; 4. enable online payment for sales order; 5. open sales order in portal view; 6. attempt to pay. Issue ----- No compatible payment providers found. Cause ----- The `payment.provider._check_company_domain` is set to the default exact match, so when it's used in `_get_compatible_payment_providers`, it's unable to find any providers for the branch company. Solution -------- Set `_check_company_domain` to `check_company_domain_parent_of`. opw-5214269 Forward-Port-Of: odoo/odoo#234821 Forward-Port-Of: odoo/odoo#234763
When Odoo sends delivery information to Amazon, it now includes the carrier code required by Amazon in some countries. If the carrier cannot be matched exactly, Odoo will send a fallback value so Amazon can still process the shipment using the carrier name.
Original PR description
The `POST_ORDER_FULFILLMENT_DATA` feed that is used to push order delivery info to Amazon should follow the `OrderFulfillment` schema (see https://images-na.ssl-images-amazon.com/images/G/01/rainier/help/xsd/release_4_1/OrderFulfillment.xsd), but it was missing the `CarrierCode` element, which is required in some countries. This commit adds the missing element to the payload, with the formatted carrier name as a value. If the carrier name cannot be matched, "Other" is used as a fallback to signal Amazon that they should rely on the `CarrierName` instead. Forward-Port-Of: odoo/enterprise#99026
This fix ensures returned goods are sent to the right place: subcontracted items go to the subcontractor location, while regular supplier returns go back to the supplier. It prevents returns from being routed incorrectly when a receipt includes both subcontracted and non-subcontracted products, reducing fulfillment errors and manual corrections.
Original PR description
Steps to reproduce the bug: - Create a storable product "P1" and "P2" with vendor "azure interior" - for P2 subcontracting BoM referencing "azure interior" as subcontractor and component "C1" -…
Steps to reproduce the bug: - Create a storable product "P1" and "P2" with vendor "azure interior" - for P2 subcontracting BoM referencing "azure interior" as subcontractor and component "C1" - Create a receipt for partner "azure interior" including 1 unit of P1 and 1 unit of P2 - Validate the receipt - Create a return for both P1 and P2 Problem: A picking is created with destination location set to the subcontracting location for both products, instead of setting the partner location only for subcontracted products. Solution: Ensure only the move line for subcontracted products uses the subcontracting destination location, while other returned products go back to the supplier location. When the `picking_id.partner_id`` is changed, it triggers a write on the picking, which in turn triggers a write on its moves, but only on the ones that are not scrapped. However, since the `scrapped`` field is a stored computed field, and as it hasn't been accessed before, it needs to be computed. And because its computation depends on `location_dest_id`, that field also needs to be recomputed. as a result, the `location_dest_id`` of the moves that we manually set may be changed unexpectedly. Therefore, in the `_create_return`` function, we check that the picking’s `partner_id` is different from the moves’ partner_id before updating it, to avoid unnecessary writes and the chain of recomputations that could alter our values. Resetting the picking’s partner_id based on the move’s partner_id could actually be removed in master, as it serves no real purpose, the move.partner_id itself is already derived from the picking’s partner_id. We just keep it in stable versions to avoid any unexpected behavior changes. opw-5208289 Forward-Port-Of: odoo/odoo#234521
Users with Recruitment access can now send referral campaigns without hitting an access error, even if they do not have employee permissions. This fixes a blocking issue in the recruitment flow so eligible users can complete the campaign action normally.
Original PR description
STEP TO REPRODUCE:
------------------
1- Give to Marc Demo the right : Recruitment / Administrator (be sure he doesn't have any right on Employees)
2- Log as Marc Demo
3- Go to Recruitment
4- Click on the three dots in kanban card
5- Click on Referral Campaign
6- Click on Send
You will have an access error
This user (with these groups) should be able to send a referral campaign
task-5082344
Forward-Port-Of: odoo/enterprise#98712
Forward-Port-Of: odoo/enterprise#96746Products with a non-variant attribute and only one available option will now be matched correctly in the cart instead of being added as a new line every time. This prevents duplicate lines for the same item and makes shopping cart behavior more consistent for customers.
Original PR description
Versions -------- - 18.0+ Steps ----- 1. Have a product attribute with variant creation set to never; 2. have product using only this attribute, with only a single value; 3. open website editor on…
Versions -------- - 18.0+ Steps ----- 1. Have a product attribute with variant creation set to never; 2. have product using only this attribute, with only a single value; 3. open website editor on /shop; 4. enable add-to-cart button & save; 5. use button on the aforementioned product at least twice. Issue ----- Each time the product gets added, a new line is created. Cause ----- Because there's only a single value, the product configurator doesn't pop up by default when adding the product to the cart. Without the configurator pop-up, the `_cart_update` method doesn't receive any `no_variant_attribute_value_ids`, which are used find a matching line if the product template has any `no_variant` attribute. Solution -------- Instead of checking `product.product_tmpl._has_no_variant_attributes()`, to see if we should attempt to match `no_variant_attribute_value_ids`, check if the added product has any `no_variant` attributes that have more than one value or are optional (multi-checkbox). If not, a `no_variant` product behaves the same as a single-variant product. opw-5093175 opw-5137351 Forward-Port-Of: odoo/odoo#234958 Forward-Port-Of: odoo/odoo#233452
This change updates how page assets are included in the appointment and rental website snippets. It helps keep these pages working with the latest Odoo asset structure and reduces the risk of display or loading issues after upgrades.
Original PR description
See https://github.com/odoo/odoo/pull/104836 task-2963840 Forward-Port-Of: odoo/enterprise#98250 Forward-Port-Of: odoo/enterprise#35153
This change stops website assets from being accidentally turned off when modules are updated. It helps keep older page elements working correctly, while unused assets are still cleaned up later by the system's regular maintenance process.
Original PR description
Before this commit when a module was updated all ir.asset records were reset to their defined `active` state, if defined. This causes assets related to old snippet versions to be made inactive even…
Before this commit when a module was updated all ir.asset records were
reset to their defined `active` state, if defined.
This causes assets related to old snippet versions to be made inactive
even if those old snippet versions are used inside existing pages.
It used to work when the activation of assets was made through view
inheritance because when views are defined through a `<template>` tag,
the `active` attribute is in fact ignored during updates since [1],
except for new records since [2].
This commit introduces an `<asset>` tag in the XML import format.
It is an alias of `<record ... model="ir.asset">` with the additional
feature that it avoids taking the `active` field into account during
updates for existing `ir_asset` records, just like `<template>` if the
`active` field is mentioned as attribute of the tag.
We then rely on the `website_disable_unused_snippets_assets` cron to
properly disable any unused asset at a later stage (note that the bug
being fixed here was mitigated by the fact that cron also re-enabled
assets which were disabled by mistake... but that might happen only a
few days later).
Another approach was to overload `_load_records_write` in `base`'s
`ir_asset.py` to avoid taking the `active` field into account when
updating records:
```py
def _load_records_write(self, values):
values.pop('active', None)
super()._load_records_write(values)
```
But this is not as stable because it changes the way `ir.asset` records
are imported when the `<record>` tag is used. In the end we chose to be
consistent and do exactly the same as `<template>`, as this also allows
more and should be entirely stable.
[1]: https://github.com/odoo/odoo/commit/2d296cb77922d33be2dc45b900191fac34bda429#diff-175c28787c272a219b9275f79262a48af9aa029e718f45077fd609737559e84eR803-R804
[2]: https://github.com/odoo/odoo/commit/f1c70d4cc943ac4eb81a85a9dc005de34cd2060a#diff-175c28787c272a219b9275f79262a48af9aa029e718f45077fd609737559e84eR801-R804
task-2963840
(Follow-up of https://github.com/odoo/upgrade/pull/3829)
Forward-Port-Of: odoo/odoo#233402
Forward-Port-Of: odoo/odoo#104836When users click a channel in the Discuss kanban view, Odoo now opens the channel’s form view instead of doing nothing. This makes it easier to review and manage channel details directly from the channel list.
Original PR description
**Steps to reproduce:** Open 'Discuss' Click on 'Channel' in the menu to display channels in kanban view Click on any channel **Cause**: The action 'mail.discuss_channel_action' did not include form view in view_mode. **Effect**: Clicking on a kanban card does not display the form view. **Fix**: Open the form view of a channel when clicking on a kanban card. Task-5076555 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This change prevents Spreadsheet from crashing when users freeze and share a sheet that includes a boolean global filter. It ensures Excel export works reliably even when a filter has no selected value, avoiding interruptions for users.
Original PR description
The method `getFilterDisplayValue` would not handled `undefined` values for boolean global filters, causing crashes when exporting to Excel. Task: [5188932](https://www.odoo.com/web#id=5188932&cids=1&menu_id=4720&action=333&active_id=2328&model=project.task&view_type=form) 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 change updates Odoo’s email server handling so it works correctly on newer Debian Trixie environments. It prevents mail-related warnings and failures caused by changes in how system libraries handle secure connections and local address resolution.
Original PR description
Forward-Port-Of: odoo/odoo#234020 Forward-Port-Of: odoo/odoo#232699
This change stops Hoot tests from creating unnecessary IndexedDB databases during full test runs. It helps keep automated testing cleaner and more reliable, while IndexedDB coverage remains in dedicated tests.
Original PR description
Disable IndexedDB in Hoot tests to avoid creating to much IndexedDB databases when running the full test suite. IndexedDB is still tested in dedicated tours.
This fix ensures Odoo only uses one matching default record when saving a default value. It prevents a rare crash caused by duplicate records, so users can set defaults without interruption.
Original PR description
There’s no constraint preventing duplicate `ir.default` records. When setting a default using `self.env['ir.default'].set()`, it searches for an existing one, but if more than one match is found,…
There’s no constraint preventing duplicate `ir.default` records. When setting a default using `self.env['ir.default'].set()`, it searches for an existing one, but if more than one match is found, accessing `default.json_value` raises a singleton error.
This fix makes sure the search only picks one record, avoiding that crash.
Before fix:
```py
self: res.users(1,)
>>> company = self.company_id
>>> company
res.company(1,)
>>> self.env['ir.default'].create({'field_id': 4540, 'company_id': company.id, 'json_value': 7})
ir.default(9,)
>>> self.env['ir.default'].set('res.partner', 'property_account_receivable_id', 7, company_id=company.id)
Traceback (most recent call last):
File "/home/odoo/odoo/odoo/odoo/orm/models.py", line 5630, in ensure_one
_id, = self._ids
^^^^
ValueError: too many values to unpack (expected 1)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/odoo/odoo/odoo/odoo/addons/base/models/ir_default.py", line 107, in set
if default.json_value != json_value:
^^^^^^^^^^^^^^^^^^
File "/home/odoo/odoo/odoo/odoo/orm/fields.py", line 1670, in __get__
record.ensure_one()
File "/home/odoo/odoo/odoo/odoo/orm/models.py", line 5633, in ensure_one
raise ValueError("Expected singleton: %s" % self)
ValueError: Expected singleton: ir.default(4, 9)
```
After fix:
```py
self: res.users(1,)
>>> company = self.company_id
>>> company
res.company(1,)
>>> self.env['ir.default'].create({'field_id': 4540, 'company_id': company.id, 'json_value': 7})
ir.default(10,)
>>> self.env['ir.default'].set('res.partner', 'property_account_receivable_id', 7, company_id=company.id)
True
```
opw-5228419
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#234944
Forward-Port-Of: odoo/odoo#2348934 changes
Resolved issues and error corrections
This update corrects two issues that could prevent DHL shipments and return labels from being created successfully. It fixes a misspelled customer reference field and adjusts the shipping date format to match DHL’s required format, reducing failed deliveries and manual rework.
Original PR description
Currently, when creating a DHL shipment with an export declaration that includes a customer reference, there is a misspelling of the field 'recipientReference' as 'recepientReference'. This causes…
Currently, when creating a DHL shipment with an export declaration that includes a customer reference, there is a misspelling of the field 'recipientReference' as 'recepientReference'. This causes validation errors when communicating with the DHL API. In addition, the datetime format used for the planned shipping date and time does not conform to the expected format specified by DHL. Steps to reproduce spelling issue: 1. Create a Sales Order with a customer reference and a deliverable product. 2. Validate the SO. 3. Go to the delivery, select DHL as carrier, and confirm. → Error: Validation error #/content/exportDeclaration: extraneous key [recepientReference] is not permitted. Steps to reproduce datetime issue: 1. Create a delivery using the DHL carrier. 2. Confirm the delivery. 3. Return the delivery. 4. Click "Print Return Label". → Error: Bad request #/plannedShippingDateAndTime is not well formatted (expected format: '2010-02-11T17:10:09 GMT+01:00'). Official DHL documentation: https://developer.dhl.com/sites/default/files/2025-11/dpdhl-express-api-3.1.1_swagger.yaml opw-5024363 Forward-Port-Of: odoo/enterprise#98981
Amazon order delivery updates now include the carrier code when Odoo sends fulfillment information. This helps ensure shipments are accepted correctly in countries where that field is required, reducing the risk of delivery sync issues.
Original PR description
The `POST_ORDER_FULFILLMENT_DATA` feed that is used to push order delivery info to Amazon should follow the `OrderFulfillment` schema (see https://images-na.ssl-images-amazon.com/images/G/01/rainier/help/xsd/release_4_1/OrderFulfillment.xsd), but it was missing the `CarrierCode` element, which is required in some countries. This commit adds the missing element to the payload, with the formatted carrier name as a value. If the carrier name cannot be matched, "Other" is used as a fallback to signal Amazon that they should rely on the `CarrierName` instead. Forward-Port-Of: odoo/enterprise#99026
When a pivot table is sorted by a date or date-time field in the web view, inserting it into a spreadsheet now keeps the same sort order. This fixes an issue where the date values were not normalized correctly, which could make the spreadsheet version appear unsorted.
Original PR description
If on the web pivot view we create a pivot with a date/dateTime field in the columns, and sort on one of these columns, the resulting pivot when inserted in a spreadsheet isn't sorted. This was because we didn't normalize the date values in the pivot `sortedColumn`, and we had UTC timestamps `2023-01-01 00:00:00` instead of normalized values `01/2023`. Task: [3575465](https://www.odoo.com/web#id=3575465&cids=1&menu_id=4720&action=333&active_id=2328&model=project.task&view_type=form)
Code cleanup and technical improvements
The update replaces older text-matching selectors with a newer, more precise option in the affected test code. This helps keep automated tests reliable and easier to maintain without changing business functionality.
Original PR description
This commit replaces all found occurrences where ':contains' (with an exact match regular expression) could be replaced by ':text'. Community: https://github.com/odoo/odoo/pull/234331 Forward-Port-Of: odoo/enterprise#98772
24 changes
Enhancements to existing features
Australian payroll now handles flexible employee benefits through salary-rule based inputs rather than separate employee version fields. This aligns the localization with the newer benefits system, making benefits easier to manage consistently in payroll calculations, reporting, and related accounting flows.
Original PR description
purpose: adapting the new system of flexible benefits coming from salary rules for au localization - adapted the fields in `hr.version` to become salary rules with `condition_select` as `property_input` which makes it appear in the input section Task: 5122332
Employee payslips in India payroll no longer show internal salary rule descriptions meant for HR teams. This keeps payslips clearer for employees and prevents long internal notes from being cut off in the document.
Original PR description
Salary rule descriptions are intended for HR officers, not employees. Displaying them on the employee payslip is unnecessary and causes cropping issues when the text is too long. task-4984330
This update prepares Studio-related test environments for offline behavior, helping ensure the interface works reliably when offline support is enabled. It also makes an existing Studio test more dependable by avoiding clicks on a disabled menu icon.
The Indian Payroll payment advice wizard now lets users indicate whether a payment is made by cheque. When cheque payment is not used, the report hides cheque details instead of showing placeholder text, making payment advice documents clearer and more professional.
Original PR description
This commit allows the payment advice wizard to have the option of not using a cheque and therefore hiding the cheque details from the report if it is not needed instead of having XXXXXXXX as a placeholder. Task-ID: 5231902
Payroll now alerts users when a payslip's net pay is zero or negative. This helps payroll teams spot unusual or potentially incorrect payslips before processing, reducing the risk of payment mistakes.
Original PR description
If the net pay for the payslip is either less than or equal to zero, a warning message will appear
Saudi payroll employer costs now include allowances and company-paid items such as work permits, iqama, and medical insurance, giving businesses a fuller view of employment expenses. Immigration-related employee fields are also shown only when relevant and grouped with employer costs for clearer payroll management.
Original PR description
Previously, the Employer Costs section only considered the employee's basic wage and did not include additional expenses such as allowances or work permit/visa-related fees. This improvement updates the employer cost calculation to include: - Allowances (housing, transportation, and other) - Work permit, iqama, and medical insurance costs At the payslip level, the following salary rules now contribute to the employer costs: - Net - GOSI - Company Contribution - GOSI - Employee Contribution - Medical Insurance (Company Contribution) - Iqama (Company Contribution) - Work Permit (Company Contribution) Additionally: - Fields related to immigrant workers are now only visible for non-Saudi employees. - These fields have been moved under the Employer Costs section. Task - 5064850
The UAE payroll payment report has been adjusted to match Dubai Islamic Bank's expected WPS format, helping businesses submit salary payments with fewer bank rejections. A scheduled monthly update was also added to keep employee leave day values current for payroll processing.
Original PR description
The format of the payment report has been adjusted to adhere to the expected format of Dubai Islamic Bank.
The Payroll menu item previously called "Employment Types" is now labeled "Contract Types." This makes the wording consistent with the Employee module and helps users find the same concept under the same name across the system.
Original PR description
- Renamed the (hr_contract_type_action) menu item from (Employment Types) to (Contract Types) for consistency with the Employee module. task-5118865
Payroll percentage and rate fields are now stored consistently as fractional values and displayed using the percentage format. This improves clarity and consistency across payroll screens, reports, demo data, and tests in several country-specific payroll modules.
Original PR description
Generalised the definition of fields displayed as percentages to be fractional numbers (ratio of 1.0) rather than whole numbers (ration of 100.0), and used the percentage widget to display them all. task-4987743
Saudi Arabia payroll now has a dedicated payslip printout that better matches local payroll expectations. The report removes fields that are not needed for this localization and adjusts the layout to make payslips clearer and more relevant for Saudi employees and payroll teams.
Original PR description
- Introduce a dedicated payslip printout tailored for Saudi localization. - Remove unnecessary fields from the default format and adjust the layout to match Saudi payroll requirements. Task: 5126583 Forward-Port-Of: odoo/enterprise#96373
This update improves how records are loaded in several Odoo apps, reducing unnecessary database work while keeping computed information accurate. Users should see more reliable behavior in affected areas such as projects, appointments, payroll, assets, knowledge, and Amazon sales integrations.
Original PR description
Fix a computed field which is now called with several records because of better prefetching.
The GST report columns for India have been reordered so IGST appears before CGST. This aligns Odoo reports with the government portal layout, making comparisons and submissions easier for users.
Original PR description
In this PR, the IGST column is moved before the CGST column to match the government portal report layout and provide a better user experience. task-5244841 Forward-Port-Of: odoo/enterprise#99062
Resolved issues and error corrections
Fixes an issue where editing a website checkout page after adding a rental-related product could trigger an error due to repeated tooltip cleanup. The change limits cleanup to the intended rental information messages, making the checkout and website editing flow more reliable.
Original PR description
Following commits odoo/odoo@d37d908 and odoo/enterprise@901b8ea, the tooltip cleanup logic disposes elements in `website_sale_renting`, and when the same logic runs again in `payment`, it tries to…
Following commits odoo/odoo@d37d908 and odoo/enterprise@901b8ea, the tooltip cleanup logic disposes elements in `website_sale_renting`, and when the same logic runs again in `payment`, it tries to dispose them a second time, causing a null element error.
Steps to reproduce:
1. Install `website_sale_renting`
2. Install a demo payment method
3. Go to the shop, add any product to the cart, proceed to payment
4. Click the "Edit" button on the website → observe the error
```js
web.assets_frontend_lazy.min.js:3912 TypeError: Cannot read properties of null
(reading 'closest') at Tooltip.dispose (web.assets_frontend_lazy.min.js:2710:70)
at PaymentForm.<anonymous> (web.assets_frontend_…zy.min.js:8282:1450)
at Colibri.destroyInteraction (web.assets_frontend_lazy.min.js:6472:68)
at Colibri.destroy (web.assets_frontend_lazy.min.js:6524:55)
at InteractionService.stopInteractions (web.assets_frontend_lazy.min.js:6584:162)
at InteractionService.stopInteractions (web.assets_frontend_lazy.min.js:6625:907)
at stop (website.assets_insid…rame.min.js:137:290)
at HTMLDocument.<anonymous> (website.assets_insid…rame.min.js:153:450)
at WebsiteBuilderClientAction.onEditPage (web.assets_web.min.js:22215:55)
```
- Restrict tooltip handling to elements with the .o_rental_info_message class to ensure only the intended elements are selected.
- This fix ensures tooltip cleanup is performed safely without re-disposing already disposed elements.
Forward-Port-Of: odoo/enterprise#98748Amazon order fulfillment updates now include the carrier code required in some countries. This helps delivery confirmations match Amazon's expected format and reduces the risk of rejected or incomplete shipment updates.
Original PR description
The `POST_ORDER_FULFILLMENT_DATA` feed that is used to push order delivery info to Amazon should follow the `OrderFulfillment` schema (see https://images-na.ssl-images-amazon.com/images/G/01/rainier/help/xsd/release_4_1/OrderFulfillment.xsd), but it was missing the `CarrierCode` element, which is required in some countries. This commit adds the missing element to the payload, with the formatted carrier name as a value. If the carrier name cannot be matched, "Other" is used as a fallback to signal Amazon that they should rely on the `CarrierName` instead. Forward-Port-Of: odoo/enterprise#99026
The Sign app now handles unsupported file uploads properly when debug mode is enabled. Instead of showing a technical crash, users see a clear message explaining that the file type is not supported.
Original PR description
Version: - saas-18.3 Steps to reproduce: - Enable debug mode. - Try uploading a non-PDF file in the Sign app. Before: - Uploading a non-PDF file in debug mode caused a traceback error. - The TemplateAlertDialog component tried to use a message prop that wasn’t defined. After: - Replaced the use of the undefined message prop with the correct body prop to display the error message. Impact: - Fixes the traceback error in debug mode. - Shows a clear and user-friendly error message when uploading unsupported file types. task-4828439 Forward-Port-Of: odoo/enterprise#89081
This fix makes Shiprocket delivery tax processing more robust when India GST tax data is not available. It also stabilizes related tests by using a consistent tax rate, reducing false failures and improving reliability.
Original PR description
Some other test adds a fiscal position with tax mapping. This creates 2 problems 1. The new taxes have a tag, which means we evaluate the right hand of…
Some other test adds a fiscal position with tax mapping. This creates 2 problems
1. The new taxes have a tag, which means we evaluate the right hand of
https://github.com/odoo/enterprise/blob/8d3fe30c627eada1186c15480876fb2e8f7ddb59/delivery_shiprocket/models/shiprocket_request.py#L239
However, since l10n_in is not installed,
`tax.env.ref(f"l10n_in.tax_tag_{gst}gst", False)`
does not return anything (False is not a fallback)
https://github.com/odoo/odoo/blob/1e96a3d127e8f521d3027f7110026ae84e11ed5e/odoo/api.py#L588
So we end up looking for `None` in `tax_tag_ids`, which leads us to compare the `_name` properties, see
https://github.com/odoo/odoo/blob/1e96a3d127e8f521d3027f7110026ae84e11ed5e/odoo/models.py#L6545-L6558
2. The test added in 4d5df93 was assuming the default company 15% tax, which was not always true
Solution
-----
1. Provide a fallback for the `ref` lookup
2. Force a 15% tax in the test
-----
runbot-232692
Forward-Port-Of: odoo/enterprise#99027
Forward-Port-Of: odoo/enterprise#97998Fixed an issue where converting very large Excel files with many sheets into Odoo spreadsheets could fail with an error. This improves reliability for users working with complex uploaded spreadsheets in Documents.
Original PR description
Steps to reproduce: - upload a large xlsx file (e.g. with >1000 sheets) - open it and convert it to o-spreadsheet => traceback Task: 5222481 Forward-Port-Of: odoo/enterprise#99087 Forward-Port-Of: odoo/enterprise#98443
Fixes Swedish POS fiscal reporting so sales orders are correctly validated through the required blackbox process again. It also restores reliable receipt reprint tracking and corrects the organisation number format, helping businesses stay compliant with Swedish point-of-sale requirements.
Original PR description
Before this commit, the Swedish blackbox was completely broken in 18.0 because the `push_single_order` function is no longer used. To fix this, the same approach as `pos_blackbox_be` was used, where the `preSyncAllOrders` function was overridden instead. In addition, the old receipt reprinting logic was no longer working, and so it now uses the `nb_print` field to keep track of the number of reprints. Finally, we also forward port a fix from 17.0 (ddbc1fc) to correct the format of the organisation number, which for some reason was not forward ported originally. task-5077448 Forward-Port-Of: odoo/enterprise#98437 Forward-Port-Of: odoo/enterprise#98139
This fix ensures payroll work entries stay accurate when employee attendance records are created, edited, or deleted. It prevents duplicate, missing, or wrongly removed work entries so payroll calculations better reflect actual attendance time.
Original PR description
[FIX] hr_work_entry: fix work entries not being regenerated on attendance modification Steps to reproduce: - In Attendance, create, modify or delete an attendance - In Payroll, go to the work entries…
[FIX] hr_work_entry: fix work entries not being regenerated on attendance modification Steps to reproduce: - In Attendance, create, modify or delete an attendance - In Payroll, go to the work entries tab - If creating an attendance, work entries with the previous and current attendance duration will be displayed - If modifying an attendance, changing the duration would not create a new work entry nor modify the existing one(s) - If deleting an attendance, the work entry would be deleted even if there were other attendances on the same day Reason: - For creation, the method creating work entries from attendances had a strict inequality, which caused the check to never trigger. - For modification, nothing was done to regenerate the work entry after editing the duration. - For deletion, the method archived work entries regardless of whether or not there were other attendances in the day. How it was fixed: - For creation, changed the strict inequalities to inequalities to allow the check for work entries to be made - For modification, if the check in or check out dates are changed, triggers the regeneration of linked worked entries - For deletion, the work entry is only deleted when no attendances are left, and then regenerate work entries to match the new total attendance duration Task ID: 5116353 Forward-Port-Of: odoo/enterprise#96635
The Accounting Reports control panel now handles narrow mobile screens correctly. Users can scroll horizontally within the report controls while the header remains stable, making reports easier to use on phones.
Original PR description
Before this commit, the control panel had an overflow in mobile view. The classes `mx-auto` and `fit-content` were causing the issue, so they got taken out. The class `overflow-x-auto` got put in to manage the horizontal overflow and get a horizontal scroll on the content so the header could stay fixed. task-4768525
Quality checks created during receipt confirmation now use the company from the related stock move line instead of the currently active company. This prevents errors when users confirm Company B receipts while working from Company A, improving reliability for multi-company operations.
Original PR description
When creating quality checks per quantity, a multi-company error occurs if the active company differs from the one defined on the control point. Steps to reproduce: - Create a Quality Control Point for Company B and Product Table for the receipt operation with a per-quantity control. - Create a receipt in Company B for this product but leave it in draft. - Switch to Company A and try to confirm → error. Root cause: The company_id was not set when creating the quality check, causing it to default to `env.company` (A) instead of the stock move line’s company (B). opw-86993 Forward-Port-Of: odoo/enterprise#99076 Forward-Port-Of: odoo/enterprise#98655
This fixes a display issue in the Gantt view where the empty-state helper’s blur effect could appear over other page elements. Users should see cleaner screens when no Gantt content is available, without visual obstruction of nearby controls or components.
Original PR description
This commit resets the `position` and `top` attributes in `gantt_view.scss` causing the previously implemented opacity blur effect of the nocontent helper to wrongly appear on top of some components. task-5245728 Forward-Port-Of: odoo/enterprise#98997
The sitemap now only lists the Helpdesk page for websites where Helpdesk is actually enabled. This prevents visitors and search engines from seeing links to Helpdesk pages on websites that do not offer that service.
Original PR description
Steps to reproduce: 1) Create two websites(Website A, Website B) in one company 2) Configure domains in both websites, for example, http://localhost:8069 for Website A, http://127.0.0.1:8069 for Website B 3) In Helpdesk team settings, enable Website Form and select Website A as the website for the helpdesk 4) Now go to browser, and open http://127.0.0.1:8069/sitemap.xml Current Behaviour: Website B will show <loc>http://127.0.0.1:8069/helpdesk</loc> in sitemap even though Website B has no Helpdesk Team! Solution: This commit will add a sitemap method, that will only show the helpdesk in sitemap if it's enabled Forward-Port-Of: odoo/enterprise#96912
This fix updates an automated test so it runs under the same project user permissions expected in normal use. It prevents misleading test failures caused by administrator-level access, helping keep project budgeting quality checks reliable.
Original PR description
In commit [1], a new test was added, but it fails because the result of `template_values` does not match the expected outcome. The failure occurs at line [2], where the method `_get_profitability_values` is called with the project's environment. This environment includes the superuser, which causes the discrepancy in the result. This commit resolves the issue by calling the project (self.project_goats) with the user set to `self.user_projectuser`. [1]: https://github.com/odoo/enterprise/commit/29c6e1d648218219c718a0448fffb8b8444af5df [2]: https://github.com/odoo/odoo/blob/fad692777e90f3c91f91d2a91e706f8bdb64a08a/addons/project/models/project_update.py#L116 runbot-233851 Forward-Port-Of: odoo/enterprise#98897
26 changes
Enhancements to existing features
The Saudi localization demo data has been updated so the Sandbox uses current company, partner, and tax information. This helps the latest validation checks run cleanly and avoids warning messages in demo setups.
Original PR description
Our demo data for the Sandbox was outdated, and the new validations for the Other Seller ID triggered warnings. This commit updates the data to include the latest taxes, partners, and company details to ensure all validations pass. task-5152670 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The bank statement validation check was optimized to run much faster by using a more efficient database query. This reduces processing time and database load, which can help the accounting app respond more quickly when checking many statements.
Original PR description
Description ----------- Avoid self-join of `account_bank_statement` that is done with a `Nested Loop` due to the `LATERAL`. Even if correlated, it requires two separate accesses to its index. Replaces it with a window function + `LAG` partitioned by the `journal_id`. This leads to a simpler plan (lower cost) and working in-memory instead of accessing disk pages (lower IO contention). Benchmark --------- On a database with 46k `account_bank_statement`, calling `_get_invalid_statement_ids` for all statements took: | [Before](https://explain.dalibo.com/plan/7605a4ddc42afbcf) | [After](https://explain.dalibo.com/plan/88d6ac1gee37aha3) | Speed-up | |--------|-------|----------| | 146ms | 72ms | 2x | --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#232980
The IGST column has been moved before the CGST column in Indian GST reports. This makes the reports match the government portal more closely and improves readability for users reviewing tax data.
Original PR description
In this PR, the IGST column is moved before the CGST column to match the government portal report layout and provide a better user experience. task-5244841
The VoIP app now uses the official country data stored in Odoo instead of a hard-coded flag mapping. This fixes cases where some places were shown with the wrong flag or country name, making contact information more accurate and consistent.
Original PR description
Previously, we hard-coded the URL according to the country code to display a country flag. However, this is not the case for all countries. Countries like Bonaire, Sint Eustatius, and Saba use the flag of the Netherlands. Additionally, Bonaire, Sint Eustatius, and Saba are shown as Caribbean Netherlands, which is inconsistent with the data from our res.country model. This commit changes it to use the data from res.country. Task-5207454 Forward-Port-Of: odoo/enterprise#99042 Forward-Port-Of: odoo/enterprise#98756
Resolved issues and error corrections
This change prevents the breadcrumb title from briefly changing to an incorrect label when users switch between livechat sessions. It improves the browsing experience by keeping the session name stable and accurate while navigating.
Original PR description
Before this PR, The breadcrumbs flickered when navigating between livechat sessions. This occurred because the `FormController`…
Before this PR,
The breadcrumbs flickered when navigating between livechat sessions.
This occurred because the `FormController` ([@web/views/form/form_controller](https://github.com/odoo/odoo/blob/saas-18.3/addons/mail/static/src/core/web/discuss_patch.js#L16-L23))
updated the breadcrumb title inside the `onRendered` hook and set it to
`this.model.root.data.display_name` which is `undefined`, the `Discuss` component
also updated the breadcrumb title in a `useEffect` hook. ([@mail/code/web/discuss_patch.js](https://github.com/odoo/odoo/blob/saas-18.3/addons/mail/static/src/core/web/discuss_patch.js#L16-L23))
The two updates conflicted: the onRendered hook first set the title to
“Unnamed,” and then the useEffect hook replaced it with the correct title,
causing a brief flicker. Additionally, when navigating to another session with
the same thread.displayName, the useEffect hook did not trigger (since its
dependency did not change), but onRendered still ran, causing the breadcrumb
to remain “Unnamed”.
This PR fixes the issue by introducing a `LivechatFormController` which
updates the breadcrumbs when channel is fetched in store.
task-4671251
Before:

After:

task-4671251
Forward-Port-Of: odoo/odoo#233167This change prevents the Helpdesk page from appearing in a website’s sitemap unless Helpdesk is actually enabled for that site. It avoids exposing links on websites that do not have a Helpdesk team configured, which keeps site maps accurate for visitors and search engines.
Original PR description
Steps to reproduce: 1) Create two websites(Website A, Website B) in one company 2) Configure domains in both websites, for example, http://localhost:8069 for Website A, http://127.0.0.1:8069 for Website B 3) In Helpdesk team settings, enable Website Form and select Website A as the website for the helpdesk 4) Now go to browser, and open http://127.0.0.1:8069/sitemap.xml Current Behaviour: Website B will show <loc>http://127.0.0.1:8069/helpdesk</loc> in sitemap even though Website B has no Helpdesk Team! Solution: This commit will add a sitemap method, that will only show the helpdesk in sitemap if it's enabled
This update corrects a DHL field name used for customer references, preventing shipment validation errors when sending export declarations. It also adjusts the planned shipping date/time format to match DHL’s required standard, so return labels and related shipping actions complete successfully.
Original PR description
Currently, when creating a DHL shipment with an export declaration that includes a customer reference, there is a misspelling of the field 'recipientReference' as 'recepientReference'. This causes…
Currently, when creating a DHL shipment with an export declaration that includes a customer reference, there is a misspelling of the field 'recipientReference' as 'recepientReference'. This causes validation errors when communicating with the DHL API. In addition, the datetime format used for the planned shipping date and time does not conform to the expected format specified by DHL. Steps to reproduce spelling issue: 1. Create a Sales Order with a customer reference and a deliverable product. 2. Validate the SO. 3. Go to the delivery, select DHL as carrier, and confirm. → Error: Validation error #/content/exportDeclaration: extraneous key [recepientReference] is not permitted. Steps to reproduce datetime issue: 1. Create a delivery using the DHL carrier. 2. Confirm the delivery. 3. Return the delivery. 4. Click "Print Return Label". → Error: Bad request #/plannedShippingDateAndTime is not well formatted (expected format: '2010-02-11T17:10:09 GMT+01:00'). Official DHL documentation: https://developer.dhl.com/sites/default/files/2025-11/dpdhl-express-api-3.1.1_swagger.yaml opw-5024363 Forward-Port-Of: odoo/enterprise#98981
This fix ensures pricelist rules entered on a product variant are properly saved after you click Save. It prevents users from losing pricing changes, improving reliability when managing product prices in Sales.
Original PR description
steps to reproduce: ------------------- 1. Install sales 2. Enable Product Variants and Pricelists under Sales > Configuration 3. Open a product variant and create a pricelist rule 4. Save it issue:…
steps to reproduce: ------------------- 1. Install sales 2. Enable Product Variants and Pricelists under Sales > Configuration 3. Open a product variant and create a pricelist rule 4. Save it issue: ----- The pricelist rules are not saved. cause: ------ The field `pricelist_rule_ids` on `product.product` is a non-stored One2many. https://github.com/odoo/odoo/blob/b1041951d436b4b6adc90d8b8dd7b8c88cc69a46/addons/product/models/product_product.py#L62-L68 In the ORM, such fields are handled in the else part of [write_real()](https://github.com/odoo/odoo/blob/b1041951d436b4b6adc90d8b8dd7b8c88cc69a46/odoo/orm/fields_relational.py#L1033-L1049), Since this field is non-stored, it has no corresponding column in the database to persist changes. As a result, any updates made to it are lost after saving. solution: --------- Add an inverse method to make the field writable. opw-5097909 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#229521
When creating a new employee, the system now pulls the work address from the active company instead of the current user’s company. This ensures employees created in a different company start with the right address automatically.
Original PR description
Steps to reproduce: - Open the Employee app. - Create a new employee in a company different from the current user's company. Issue: - The default address is taken from the current user's company instead of the active company's address. Fix: - Default address now uses the active company's address instead of the user's company. task-5138714 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#230049
The invoice synchronization process was using the wrong company in some cases. This update ensures invoices are grouped by company and synced separately, reducing the risk of incorrect synchronization results.
Original PR description
The sync process previously used the wrong company when synchronizing invoices. This fix groups invoices by their respective companies and performs the sync for each company individually. task-5207338 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#233148
This change prevents an error from appearing when someone uploads a non-PDF file in the Sign app while debug mode is enabled. Instead of a traceback, users now see a clear and friendly message explaining that the file type is not supported.
Original PR description
Version: - saas-18.3 Steps to reproduce: - Enable debug mode. - Try uploading a non-PDF file in the Sign app. Before: - Uploading a non-PDF file in debug mode caused a traceback error. - The TemplateAlertDialog component tried to use a message prop that wasn’t defined. After: - Replaced the use of the undefined message prop with the correct body prop to display the error message. Impact: - Fixes the traceback error in debug mode. - Shows a clear and user-friendly error message when uploading unsupported file types. task-4828439 Forward-Port-Of: odoo/enterprise#89081
This update makes Shiprocket work reliably when local GST tax labels are not available, preventing shipping-related errors in affected setups. It also corrects the test scenario so it uses a consistent tax rate, avoiding flaky test behavior.
Original PR description
Some other test adds a fiscal position with tax mapping. This creates 2 problems 1. The new taxes have a tag, which means we evaluate the right hand of…
Some other test adds a fiscal position with tax mapping. This creates 2 problems
1. The new taxes have a tag, which means we evaluate the right hand of
https://github.com/odoo/enterprise/blob/8d3fe30c627eada1186c15480876fb2e8f7ddb59/delivery_shiprocket/models/shiprocket_request.py#L239
However, since l10n_in is not installed,
`tax.env.ref(f"l10n_in.tax_tag_{gst}gst", False)`
does not return anything (False is not a fallback)
https://github.com/odoo/odoo/blob/1e96a3d127e8f521d3027f7110026ae84e11ed5e/odoo/api.py#L588
So we end up looking for `None` in `tax_tag_ids`, which leads us to compare the `_name` properties, see
https://github.com/odoo/odoo/blob/1e96a3d127e8f521d3027f7110026ae84e11ed5e/odoo/models.py#L6545-L6558
2. The test added in 4d5df93 was assuming the default company 15% tax, which was not always true
Solution
-----
1. Provide a fallback for the `ref` lookup
2. Force a 15% tax in the test
-----
runbot-232692
Forward-Port-Of: odoo/enterprise#99027
Forward-Port-Of: odoo/enterprise#97998This change corrects a test that was failing when a project was added because it was using the wrong user context. By running the project with the expected project user instead of superuser access, the test now matches the intended business behavior.
Original PR description
In commit [1], a new test was added, but it fails because the result of `template_values` does not match the expected outcome. The failure occurs at line [2], where the method `_get_profitability_values` is called with the project's environment. This environment includes the superuser, which causes the discrepancy in the result. This commit resolves the issue by calling the project (self.project_goats) with the user set to `self.user_projectuser`. [1]: https://github.com/odoo/enterprise/commit/29c6e1d648218219c718a0448fffb8b8444af5df [2]: https://github.com/odoo/odoo/blob/fad692777e90f3c91f91d2a91e706f8bdb64a08a/addons/project/models/project_update.py#L116 runbot-233851
When a product with only one non-variant option was added to the cart from the website, it could create a new line every time instead of updating the existing one. This fix makes those products behave like standard single-variant items, so repeat additions are handled correctly and the cart stays accurate.
Original PR description
Versions -------- - 18.0+ Steps ----- 1. Have a product attribute with variant creation set to never; 2. have product using only this attribute, with only a single value; 3. open website editor on…
Versions -------- - 18.0+ Steps ----- 1. Have a product attribute with variant creation set to never; 2. have product using only this attribute, with only a single value; 3. open website editor on /shop; 4. enable add-to-cart button & save; 5. use button on the aforementioned product at least twice. Issue ----- Each time the product gets added, a new line is created. Cause ----- Because there's only a single value, the product configurator doesn't pop up by default when adding the product to the cart. Without the configurator pop-up, the `_cart_update` method doesn't receive any `no_variant_attribute_value_ids`, which are used find a matching line if the product template has any `no_variant` attribute. Solution -------- Instead of checking `product.product_tmpl._has_no_variant_attributes()`, to see if we should attempt to match `no_variant_attribute_value_ids`, check if the added product has any `no_variant` attributes that have more than one value or are optional (multi-checkbox). If not, a `no_variant` product behaves the same as a single-variant product. opw-5093175 opw-5137351 Forward-Port-Of: odoo/odoo#234958 Forward-Port-Of: odoo/odoo#233452
This change fixes an error that could prevent users from saving an overtime rule when it is based on timing. The system now provides a default timing value, avoiding the crash and making rule setup work as expected.
Original PR description
This error occurs when no `timing_type` is set for the timing in the rule.
Steps to reproduce:
---
- Install `hr_attendance` module(without demo)
- Attendance > Configurations > Overtime Rulesets
- Create New Rule > Add an overtime rule in this ruleset with:
- Rule is based on: `Timing`
- Save & Close
- Now Save Rule
Traceback:
---
`KeyError: False`
At [1], this error occurs because the rule has no `timing_type` set, as no default value for field is defined.
[1]- https://github.com/odoo/odoo/blob/6e5146113adbdce3cbe317a7b3ef16be0a244b6a/addons/hr_attendance/models/hr_attendance_overtime_rule.py#L453
sentry-6986530016
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prThe app creator in Studio now uses a border color that stands out against the background. This makes checkboxes and other boundary elements easier to see while building an app, improving usability and reducing confusion.
Original PR description
Before this commit : when creating an app using the studio, none of the borders were visible, including the checkboxes in the app creator, because the background color of the app creator and the border color were the same. After this commit: the border color for the app creator has been changed to make it visible. task-5138669
The Amazon order fulfillment data now includes the carrier code required by some countries. If the carrier cannot be identified, the system uses a safe fallback so Amazon can still process the shipment correctly.
Original PR description
The `POST_ORDER_FULFILLMENT_DATA` feed that is used to push order delivery info to Amazon should follow the `OrderFulfillment` schema (see https://images-na.ssl-images-amazon.com/images/G/01/rainier/help/xsd/release_4_1/OrderFulfillment.xsd), but it was missing the `CarrierCode` element, which is required in some countries. This commit adds the missing element to the payload, with the formatted carrier name as a value. If the carrier name cannot be matched, "Other" is used as a fallback to signal Amazon that they should rely on the `CarrierName` instead. Forward-Port-Of: odoo/enterprise#99026
This update corrects how the empty-state helper is displayed in the Gantt view. It prevents the helper’s faded overlay effect from appearing on top of other interface elements, improving readability and avoiding visual overlap issues.
Original PR description
This commit resets the `position` and `top` attributes in `gantt_view.scss` causing the previously implemented opacity blur effect of the nocontent helper to wrongly appear on top of some components. task-5245728
This update corrects how package-in-package handling is detected in barcode operations so the system keeps selecting the right package without changing the user experience. It also updates an automated test to match the revised order in which package lines are processed, helping prevent incorrect follow-up actions.
Original PR description
Some adaptations based on the community side: - Adapt the compute of `outermost_result_package_id` so nothing changes functionality-wise in barcode. - Adapt a test as the priority of move lines from 'Put in Pack' have changed. Task-5116567
This update fixes several issues around moving and splitting packed goods in stock operations. It makes pack actions more reliable, improves how package choices and labels are shown, and updates printed picking documents so warehouse users see the right package information.
Original PR description
Summary of the fixes for the Put/Pack in pack: - Avoid an error when trying to click on 'Move a Pack' on an unsaved picking. - Apply putaway rules at with multi-level packages, considering…
Summary of the fixes for the Put/Pack in pack: - Avoid an error when trying to click on 'Move a Pack' on an unsaved picking. - Apply putaway rules at with multi-level packages, considering higher-level packages first. - Consider higher-level packages when checking package routes. - Updates the picking operation pdf. - For pickings, no longer display the 'Packages' stat button if no package are set as destination. We keep it for batches however, as it's currently the only way to add entire packs into a batch. - Be more lenient with the 'Remove' button for packages in a picking. - Allow to select the right packages as destination in a picking. - Change priority of move line when using 'Put in Pack', always prioritizing `picked` lines. - Avoid `Unnamed` packages when creating a new package without a name from a list view. - Display the parent packages in the 'Pick from' auto-complete. For more detail about each fix, read the related commit. Task-5116567 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Quality checks created per quantity now keep the correct company instead of using the currently active one. This prevents errors in multi-company environments when confirming receipts that were created under a different company.
Original PR description
When creating quality checks per quantity, a multi-company error occurs if the active company differs from the one defined on the control point. Steps to reproduce: - Create a Quality Control Point for Company B and Product Table for the receipt operation with a per-quantity control. - Create a receipt in Company B for this product but leave it in draft. - Switch to Company A and try to confirm → error. Root cause: The company_id was not set when creating the quality check, causing it to default to `env.company` (A) instead of the stock move line’s company (B). opw-86993 Forward-Port-Of: odoo/enterprise#99076 Forward-Port-Of: odoo/enterprise#98655
This update adds a test to make sure channel mentions are preserved when a user edits a message using the ArrowUp shortcut in the composer. It helps prevent message edits from dropping important channel references, which keeps conversations accurate and easier to follow.
Original PR description
Follow-up of https://github.com/odoo/odoo/pull/229546 Add a test to verify that mentioned channels are correctly restored when editing a message using the ArrowUp shortcut in the composer.
This update prevents a crash that could happen when a user was redirected after their session had been refreshed. It ensures session data is saved while the needed request context is still available, so users are less likely to hit errors during normal navigation.
Original PR description
Steps to reproduce ------------------ Login to runbot, wait `odoo.http.SESSION_ROTATION_INTERVAL`s (3h) then access any page, then access any bundle using its id (not its `f'{name}-{id}') e.g.…
Steps to reproduce
------------------
Login to runbot, wait `odoo.http.SESSION_ROTATION_INTERVAL`s (3h) then access any page, then access any bundle using its id (not its `f'{name}-{id}') e.g. `/runbot/bundle/123`. Traceback: cannot use a closed cursor. It occurs when the system tries to save the session.
Traceback, explained
--------------------
1. The previous request session underwent a "soft rotation", its sid changed and it was marked "gc_previous_sessions".
2. The following request matches a route that is website & multilang, it is the case of the runbot bundle route.
3. The session was marked "gc_previous_sessions", it removes *now* the other sessions and removes the mark from the current one, this sets the current session dirty.
4. The request URL is not canonical, `_pre_dispatch` in `http_routing` abords with a redirection to `/runbot/bundle/18.0-123`.
5. The abortion (`werkzeug.exceptions.abort`) is an exception that bubbles up all the way up in the http stack, notably above `_serve_db` where `request.env.cr` is closed.
6. `odoo.http.root.__call__` ultimatelly processes the response received from `_pre_dispatch`: it calls `post_process` which call `_save_session` which sees that the current session is dirty: it attempts to save it.
7. Because there is a `session.uid`, we need to refresh the session token, for that we need an environment and a cursor.
8. Kaboom, the cursor was closed by `_serve_db`.
Problem
-------
When we set/delete items from the session, the changes are only saved in the session object in memory. The modified session is only written once, at the end of the request, if no error occured.
When we save the session, we gotta update the `session_token` value, this token is a SHA over the user's login information: active, email, password, ... and is verified upon loading the session in a future request. Should the user changes its password, a new token would be computed and all the sessions with the old token would become invalid. Should the user uses an old session, he would get redirected to /web/login.
Computing the `session_token` is mandatory when there's a `uid` inside the session, otherwise the session would be invalid. Computing it requires a valid cursor to fetch the user's active, email, password, ...
In our case, the (valid) response contained in `wekzeug.exception.abort` did bubble-up above `_serve_db`: `request.env.cr` is closed.
Solution
--------
Move the exception handling for `werkzeug.exceptions.abort` in both `_serve_nodb` and `_serve_db`. That it is in `_serve_db` makes it possible to call `_post_dispatch` with a cursor and environment that are still alive. This fixes the problem at hand.
With the above fix, comes two sanity things:
The `if session.uid and env` conditional is wrong, it must be only `if session.uid`. When there is a uid stored in the session, updating the `session_token` is mandatory. It MUST crash if `save()` is called for a session with a uid but with no environment.
The `_serve_db` method manages both the request's cursor and the `request.env` attribute. Everytime the cursor is updated (e.g. when changing from a read-only to a read+write one)This change reduces unnecessary database overhead when recalculating salary simulations for job offers. By using one database savepoint for the whole calculation instead of one per offer, it improves performance and responsiveness.
Original PR description
Savepoints are used in multiple computes related to salary simulation for an offer, because it creates and updates existing records, but those should not be committed to the database. Those are currently made for each offer that needs to be recomputed. Frequent savepoint, without commit/rollback of the whole transaction, are a performance issue at the database level. To partially alleviate this issue, this commit creates 1 savepoint for the whole compute, instead of per record to compute.
This update adjusts Odoo’s mail server handling so it works correctly on newer Debian releases and with updated Python SSL libraries. It helps prevent warning messages and connection issues when sending mail in those environments.
Original PR description
Forward-Port-Of: odoo/odoo#234020 Forward-Port-Of: odoo/odoo#232699
This update prevents a crash that could happen when multiple default records matched the same setting. The system now picks a single matching record, so users can save defaults reliably even if duplicate entries exist.
Original PR description
There’s no constraint preventing duplicate `ir.default` records. When setting a default using `self.env['ir.default'].set()`, it searches for an existing one, but if more than one match is found,…
There’s no constraint preventing duplicate `ir.default` records. When setting a default using `self.env['ir.default'].set()`, it searches for an existing one, but if more than one match is found, accessing `default.json_value` raises a singleton error.
This fix makes sure the search only picks one record, avoiding that crash.
Before fix:
```py
self: res.users(1,)
>>> company = self.company_id
>>> company
res.company(1,)
>>> self.env['ir.default'].create({'field_id': 4540, 'company_id': company.id, 'json_value': 7})
ir.default(9,)
>>> self.env['ir.default'].set('res.partner', 'property_account_receivable_id', 7, company_id=company.id)
Traceback (most recent call last):
File "/home/odoo/odoo/odoo/odoo/orm/models.py", line 5630, in ensure_one
_id, = self._ids
^^^^
ValueError: too many values to unpack (expected 1)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/odoo/odoo/odoo/odoo/addons/base/models/ir_default.py", line 107, in set
if default.json_value != json_value:
^^^^^^^^^^^^^^^^^^
File "/home/odoo/odoo/odoo/odoo/orm/fields.py", line 1670, in __get__
record.ensure_one()
File "/home/odoo/odoo/odoo/odoo/orm/models.py", line 5633, in ensure_one
raise ValueError("Expected singleton: %s" % self)
ValueError: Expected singleton: ir.default(4, 9)
```
After fix:
```py
self: res.users(1,)
>>> company = self.company_id
>>> company
res.company(1,)
>>> self.env['ir.default'].create({'field_id': 4540, 'company_id': company.id, 'json_value': 7})
ir.default(10,)
>>> self.env['ir.default'].set('res.partner', 'property_account_receivable_id', 7, company_id=company.id)
True
```
opw-5228419
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#234944
Forward-Port-Of: odoo/odoo#2348939 changes
Enhancements to existing features
The bank statement validation process was optimized to run faster on large databases. This reduces waiting time for users and lowers database load, helping the system stay more responsive.
Original PR description
Description ----------- Avoid self-join of `account_bank_statement` that is done with a `Nested Loop` due to the `LATERAL`. Even if correlated, it requires two separate accesses to its index. Replaces it with a window function + `LAG` partitioned by the `journal_id`. This leads to a simpler plan (lower cost) and working in-memory instead of accessing disk pages (lower IO contention). Benchmark --------- On a database with 46k `account_bank_statement`, calling `_get_invalid_statement_ids` for all statements took: | [Before](https://explain.dalibo.com/plan/7605a4ddc42afbcf) | [After](https://explain.dalibo.com/plan/88d6ac1gee37aha3) | Speed-up | |--------|-------|----------| | 146ms | 72ms | 2x | --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#232980
Resolved issues and error corrections
This update fixes two issues that could prevent DHL shipments from being created successfully. It corrects a misspelled field name and adjusts the date/time format to match DHL's requirements, reducing failed shipping and return label requests.
Original PR description
Currently, when creating a DHL shipment with an export declaration that includes a customer reference, there is a misspelling of the field 'recipientReference' as 'recepientReference'. This causes…
Currently, when creating a DHL shipment with an export declaration that includes a customer reference, there is a misspelling of the field 'recipientReference' as 'recepientReference'. This causes validation errors when communicating with the DHL API. In addition, the datetime format used for the planned shipping date and time does not conform to the expected format specified by DHL. Steps to reproduce spelling issue: 1. Create a Sales Order with a customer reference and a deliverable product. 2. Validate the SO. 3. Go to the delivery, select DHL as carrier, and confirm. → Error: Validation error #/content/exportDeclaration: extraneous key [recepientReference] is not permitted. Steps to reproduce datetime issue: 1. Create a delivery using the DHL carrier. 2. Confirm the delivery. 3. Return the delivery. 4. Click "Print Return Label". → Error: Bad request #/plannedShippingDateAndTime is not well formatted (expected format: '2010-02-11T17:10:09 GMT+01:00'). Official DHL documentation: https://developer.dhl.com/sites/default/files/2025-11/dpdhl-express-api-3.1.1_swagger.yaml opw-5024363 Forward-Port-Of: odoo/enterprise#98981
This change fixes a problem where setting a default value could fail if duplicate default records already existed in the system. The update makes the lookup select only one matching record, so users can save defaults reliably without encountering an error.
Original PR description
There’s no constraint preventing duplicate `ir.default` records. When setting a default using `self.env['ir.default'].set()`, it searches for an existing one, but if more than one match is found,…
There’s no constraint preventing duplicate `ir.default` records. When setting a default using `self.env['ir.default'].set()`, it searches for an existing one, but if more than one match is found, accessing `default.json_value` raises a singleton error.
This fix makes sure the search only picks one record, avoiding that crash.
Before fix:
```py
self: res.users(1,)
>>> company = self.company_id
>>> company
res.company(1,)
>>> self.env['ir.default'].create({'field_id': 4540, 'company_id': company.id, 'json_value': 7})
ir.default(9,)
>>> self.env['ir.default'].set('res.partner', 'property_account_receivable_id', 7, company_id=company.id)
Traceback (most recent call last):
File "/home/odoo/odoo/odoo/odoo/orm/models.py", line 5630, in ensure_one
_id, = self._ids
^^^^
ValueError: too many values to unpack (expected 1)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/odoo/odoo/odoo/odoo/addons/base/models/ir_default.py", line 107, in set
if default.json_value != json_value:
^^^^^^^^^^^^^^^^^^
File "/home/odoo/odoo/odoo/odoo/orm/fields.py", line 1670, in __get__
record.ensure_one()
File "/home/odoo/odoo/odoo/odoo/orm/models.py", line 5633, in ensure_one
raise ValueError("Expected singleton: %s" % self)
ValueError: Expected singleton: ir.default(4, 9)
```
After fix:
```py
self: res.users(1,)
>>> company = self.company_id
>>> company
res.company(1,)
>>> self.env['ir.default'].create({'field_id': 4540, 'company_id': company.id, 'json_value': 7})
ir.default(10,)
>>> self.env['ir.default'].set('res.partner', 'property_account_receivable_id', 7, company_id=company.id)
True
```
opw-5228419
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#234893This update fixes a spelling mistake in the Website Sale module, changing an incorrect word to the intended one. It improves the clarity and professionalism of the customer-facing text without affecting how the feature works.
Original PR description
Description of the issue/feature this PR addresses: This PR fixes a typo that was found in website_sale module. There is a mistake in writing "you" --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The Amazon delivery update now includes the carrier code expected by Amazon in the shipment data. This helps prevent shipment updates from failing in countries where that field is required, improving order tracking reliability.
Original PR description
The `POST_ORDER_FULFILLMENT_DATA` feed that is used to push order delivery info to Amazon should follow the `OrderFulfillment` schema (see https://images-na.ssl-images-amazon.com/images/G/01/rainier/help/xsd/release_4_1/OrderFulfillment.xsd), but it was missing the `CarrierCode` element, which is required in some countries. This commit adds the missing element to the payload, with the formatted carrier name as a value. If the carrier name cannot be matched, "Other" is used as a fallback to signal Amazon that they should rely on the `CarrierName` instead. Forward-Port-Of: odoo/enterprise#99026
This update adds automated tests for a sales margin scenario to make sure purchase price is recalculated correctly when a canceled order is reset, then the pricelist currency is changed. It helps prevent pricing errors for products with automated costing methods and improves confidence in future changes.
Original PR description
Description of the issue/feature this PR addresses: Test-only PR to verify `purchase_price` recomputation behavior when changing pricelist currency after order cancellation (per reviewer feedback on https://github.com/odoo/odoo/pull/232553). Current behavior before PR: No test coverage for this scenario. Desired behavior after PR is merged: Test validates correct currency conversion of `purchase_price` for AVCO/FIFO products after cancel → draft → pricelist change workflow. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fix ensures the purchase price on sales order lines is recalculated correctly when a cancelled order is returned to quotation and the pricelist currency is changed. It prevents outdated cost values from being kept, which helps maintain accurate margin calculations and reporting.
Original PR description
**Description of the issue/feature this PR addresses:** Issue: The purchase_price field in sale order lines is not recomputed when changing the pricelist to a different currency after a sales order…
**Description of the issue/feature this PR addresses:** Issue: The purchase_price field in sale order lines is not recomputed when changing the pricelist to a different currency after a sales order has been confirmed, cancelled, and set back to quotation state. This causes incorrect cost calculations and margin reporting when users need to modify the currency/pricelist of a previously confirmed order that was later cancelled and reset to draft. Affected modules: sale_stock_margin Versions affected: 16.0, 17.0, 18.0 (confirmed on 18.0) **Current behavior before PR:** When a sales order goes through the following workflow: Create a sales order with a pricelist in USD Add a product line (e.g., purchase_price shows $100.00 USD) Confirm the order (stock moves are created) Cancel the order (stock moves are set to state 'cancel' but remain in move_ids) Set the order back to quotation state Change the pricelist to one with a different currency (e.g., EUR) Result: The purchase_price remains in the original currency (USD) instead of being converted to the new currency (EUR). Root cause: The _compute_purchase_price() method in sale_stock_margin checks if move_ids exist to determine whether to use stock-based costing or fall back to the standard price from sale_margin. However, cancelled moves are still present in move_ids, causing the method to skip the currency conversion that should happen when no valid (non-cancelled) moves exist. **Desired behavior after PR is merged:** After following the same workflow: Create a sales order with a pricelist in USD Add a product line (purchase_price shows $100.00 USD) Confirm the order Cancel the order Set the order back to quotation state Change the pricelist to EUR Expected result: The purchase_price is automatically recomputed and converted to the new currency (e.g., shows €92.00 EUR based on the exchange rate). How it works: The method now filters out cancelled stock moves before checking if valued moves exist. If only cancelled moves are present, the computation is delegated to the parent sale_margin module, which properly handles currency conversion using _convert_to_sol_currency(). Video Demostration From runbot of today (10/21/2025) https://drive.google.com/file/d/1KExSzOYHAmMc10b3u_Xy5B1nWkkYOBqy/view --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
When a user deletes a rating message in the portal or related pages, the rating summary now updates right away. This keeps the displayed ratings accurate and avoids showing outdated information after a message is removed.
Original PR description
*: portal, portal_rating, website_slides PR #221050, makes it possible to properly remove a message in the portal and PR #216044 retrieves the rating cards feature. There is an overlap between what these two PRs do. When a user removes a rating message and there is a rating cards feature on the page, it should be updated. Most of the remove method changes are indeed what we did in forward port of #221050 (#222517). task-5106543
When a candidate’s name is changed, any existing follow-up activities now automatically reflect the updated name. This keeps records consistent and avoids confusion for recruiters viewing older tasks.
Original PR description
Issue: When updating an hr recruitement candidate name (stored in hr_applicant after 18.2) the name change is not updated in the name of previously created activities. Cause: The field res_name in mail.activity is computed and stored only at creation of an activity. Solution: Retrigger the compute of an activity when updating a candidates name. Task-4988342
5 changes
Resolved issues and error corrections
When users upload an image in the Website Editor for the first time, Odoo now avoids creating duplicate attachments for the same file. This reduces unnecessary storage use and keeps page media cleaner, while still applying image optimization such as resizing and web format conversion.
Original PR description
This PR aims to prevent the creation of duplicate image attachments when uploading an image for the first time in Website Editor. --- ### Steps to Reproduce 1. Open Website → Edit mode. 2. Drag and drop any snippet that contains an image (e.g., cover, banner, image block). 3. Upload an image using the image upload option. 4. Check the attachments. → You will notice multiple attachments of the same image being created(by odooBot). --- ### Impact * Prevents unnecessary saves and duplicate attachments. task-4812410
Payments now correctly generate their journal items even when the journal lines field is added to the form with Studio. This prevents draft payments from being saved without the accounting entries they need, while still preserving any custom journal lines users provide.
Original PR description
**Steps to reproduce:** 1. Install the Accounting and Studio modules. 2. Create a payment in draft state. 3. Add the `line_ids` field to the payment form view using Studio. 4. Save the payment. **Observed behavior:** * A journal entry was created, but its journal items (`line_ids`) were not computed. * The payment stayed in draft with empty journal items. * The normal flow (without the field added) worked correctly. **Cause:** * The create method only checked whether `line_ids` was missing from `vals`. When Studio adds the field to the form, it appears in `vals` even when empty. As a result, the condition failed and journal items were not generated. **Fix:** * Check both if `line_ids` is missing and if it is empty. * Always compute journal items when none are explicitly provided. * Keep existing behavior for custom journal item creation. opw-5030072
The upload button in the accounting dashboard can no longer be dragged around by mistake. This keeps the interface stable and avoids confusing shifts in the upload area while users work.
Original PR description
Issue: - In the dashboard, the upload button (purchase journal and others) could be dragged. - This caused unintended movement of the upload UI element. Fix: - Added `draggable=false` to the upload button element. - Ensures the button remains fixed and cannot be dragged around. TaskID-5114617
This change corrects how time intervals are combined so they are always cleaned up before being processed. It prevents inconsistent results and errors when different interval types are used together, improving reliability in planning-related operations.
Original PR description
## The issue Prior to this commit, the `other` parameter in the `_merge` method could belong to a different class, not necessarily an instance of `Intervals`.…
## The issue Prior to this commit, the `other` parameter in the `_merge` method could belong to a different class, not necessarily an instance of `Intervals`. https://github.com/odoo/odoo/blob/8c737601327acec1d83e1e5e3c6e66c9fd226339/addons/resource/models/utils.py#L158-L165 The comment indicates that normalization should be enforced; however, there is no corresponding reference to it within the `_boundaries` method. https://github.com/odoo/odoo/blob/8c737601327acec1d83e1e5e3c6e66c9fd226339/addons/resource/models/utils.py#L48-L53 That normalization just happens in the `__init__`. https://github.com/odoo/odoo/blob/8c737601327acec1d83e1e5e3c6e66c9fd226339/addons/resource/models/utils.py#L117-L132 ## Example For example, in Planning module, we perform operations between `Intervals` and `WorkIntervals`. The `WorkIntervals` class behaves differently from `Intervals`: while `Intervals` uses disjoint closed intervals, `WorkIntervals` uses disjoint semi-closed intervals. ## Side effects During these operations, the `_merge` method was not normalizing the `_items`, which caused inconsistencies and errors (when we are merging two unormalized intervals `([0, 10], [10, 20])` with an empty `others`). ## The fix This commit ensures that the `other` parameter is normalized before processing the `_merge` operation. The fix ensures that normalized intervals are always produced after `_merge`, even when unnormalized intervals are provided as input. ## Real case That issue has been found in that ticket: 5184291
Sales order line costs now keep updating correctly even after an order was confirmed, canceled, and then reset to draft. This prevents outdated margin and pricing information from appearing when users revise quotations.
Original PR description
Versions -------- - 17.0+ Steps ----- 1. Have a product with a purchase cost; 2. have sale margins enabled; 3. add a the product to a quotation; 4. change pricelist to one with a different currency; 5. note that the line's cost gets updated; 6. change order state to confirmed, then canceled, then back to draft; 7. change pricelist again. Issue ----- The purchase cost no longer update. Cause ----- The `_compute_purchase_price` override in `sale_stock_margin` doesn't pass the line to `super` if it `has_valued_move_ids`. This hook only checks for the existence of linked `move_ids` on the record with no regard for their state. Solution -------- 1. Move the `has_valued_move_ids` hook from `sale` to `sale_stock`. 2. Only return `True` if any of the moves aren't in draft or canceled. opw-5147321