Tuesday, May 20, 2025
18 changes · 18.0
Enhancements to existing features
Tag fields now show the available tooltip text when users hover over them, making extra context easier to access without changing the main screen. This helps users understand tag meanings or details more quickly in forms and lists.
Original PR description
https://github.com/odoo/enterprise/pull/85591
Resolved issues and error corrections
Restaurant receipt wording is now translated as complete phrases instead of separate fragments, making translations more natural across languages. This also avoids confusion between restaurant tables and spreadsheet tables in translated text.
Original PR description
Do not use t-out/t-esc to build human-readable content. This is basically the same as string concatenation. This commit wraps the entire string in a gettext call to prevent it from being split into several non-reorderable translations. As a lucky side effect, it also creates a separate translation for the word "table" (as in restaurant tables) which won't overlap with the translation for spreadsheet tables. opw-4754410
Documentation and clarification updates
This update records a signed contributor agreement for Ricardo-MC. It supports the project’s legal compliance by documenting permission for contributions to be included in Odoo.
Miscellaneous changes
This reverts commit d413a9895742594d064084cd6dafbf1f2ec97221. This fix was decided after https://github.com/odoo/enterprise/pull/74127 that was trying to prevent invoicing users to see accounting features, when it seemed to be unwanted to have the two property accounts fields required while having no CoA installed. The issue is, now when having Accounting installed, we can create a user without having CoA as these two fields are not required anymore, but we end up with a error message when cre
Original PR description
This reverts commit d413a9895742594d064084cd6dafbf1f2ec97221. This fix was decided after https://github.com/odoo/enterprise/pull/74127 that was trying to prevent invoicing users to see accounting…
This reverts commit d413a9895742594d064084cd6dafbf1f2ec97221.
This fix was decided after https://github.com/odoo/enterprise/pull/74127
that was trying to prevent invoicing users to see accounting features,
when it seemed to be unwanted to have the two property accounts fields
required while having no CoA installed.
The issue is, now when having Accounting installed, we can create a user
without having CoA as these two fields are not required anymore, but
we end up with a error message when creating an invoice ('no CoA
installed') although we could be have added accounts manually instead
of installing a CoAi (which is not possible for invoicing user).
In this situation, we should be able to create a contact, and having these
fields required will force the user to create them.
Finally, it is ok to revert the full chain, as the original issue is
fixed by this commit https://github.com/odoo/enterprise/commit/68f6c1f9fd3ff6762c98e1a405ade035129efce0
Forward-Port-Of: odoo/odoo#210344
Forward-Port-Of: odoo/odoo#209832This fix makes an internal stock landed costs test use a reliable ordering method so automated checks no longer fail unpredictably. It helps keep the development pipeline stable without changing business functionality or user workflows.
Original PR description
Issue ===== In the test `test_stock_landed_costs_lots`, there is this `assertRecordValues`: ```python self.assertRecordValues(lc.stock_valuation_layer_ids.sorted('product_id'), [ {'lot_id':…
Issue
=====
In the test `test_stock_landed_costs_lots`, there is this `assertRecordValues`:
```python
self.assertRecordValues(lc.stock_valuation_layer_ids.sorted('product_id'), [
{'lot_id': lot_product_b[0].id, 'product_id': product2.id, 'stock_valuation_layer_id': og_p2_layers[0].id, 'quantity': 0, 'value': 1.5},
{'lot_id': lot_product_b[1].id, 'product_id': product2.id, 'stock_valuation_layer_id': og_p2_layers[1].id, 'quantity': 0, 'value': 1.5},
{'lot_id': lot_product_a[0].id, 'product_id': self.product1.id, 'stock_valuation_layer_id': og_p1_layers[0].id, 'quantity': 0, 'value': 1},
{'lot_id': lot_product_a[1].id, 'product_id': self.product1.id, 'stock_valuation_layer_id': og_p1_layers[1].id, 'quantity': 0, 'value': 1},
{'lot_id': lot_product_a[2].id, 'product_id': self.product1.id, 'stock_valuation_layer_id': og_p1_layers[2].id, 'quantity': 0, 'value': 1},
])
```
This issue is sometime the records order is not the expected one.
Cause of the issue
==================
By doing `recordset.sorted('product_id')`, it will sort the records by compare their `product_id` records, using the python built-in `sorted`. The built-in `sorted` function simply check if record A is lower than record B, using the < operation. But in Odoo, comparing two recordsets is equal than comparing their ids as a `set`:
```python
def __lt__(self, other):
try:
if self._name == other._name:
return set(self._ids) < set(other._ids)
except AttributeError:
pass
return NotImplemented
```
In python, the comparaison between two sets compares is a set is a subset of the other one, which means than:
```python
{1} < {2} # is false
{1} < {2, 1} # is true
```
So, comparing SVLs by their product won't sort them by their product's id. If we want to do that, we have to explicitly do it by passing a function as the `sorted` `key` argument.
For more information, see:
-https://docs.python.org/3/library/functions.html#sorted -https://docs.python.org/3/reference/expressions.html#comparisons
runbot-build-error: 99086DIN5008 formatted reports now show partner and shipping addresses with the same font size. This fixes a visual inconsistency in printed quotations, making customer-facing documents look more polished and uniform.
Original PR description
### Steps to reproduce: - Install "l10n_din5008" - In Settings > Layout, select DIN5008 as the report layout - Create a quotation, print it - The address of the partner and the sipping address have different font size ### Cause: Since this [commit](https://github.com/odoo/odoo/commit/92e4c3cb3bec0b3d5537a50fd441a22fa6509ed1) the partner address is a span which is applied a [`font-size: 0.8em;`](https://github.com/odoo/odoo/blob/f77b40bba0c92a9a225eb7ade694e79cb804f7bf/addons/l10n_din5008/static/src/scss/report_din5008.scss#L51). But not the shipping address. ### Solution: Remove the restriction of `span` to apply the font-size. This way all text in address should have the same font-size. Before:  After:  opw-4725169
When you settle a sale order that has a payment term, it was always ignored in the PoS. But it should only be ignored when the payment term has an early discount. Steps to reproduce: ------------------- * Create a sale order with a payment term that has no early discount * Go to the PoS and settle the sale order * Invoice and validate the order > Observation: In the backend, the sale order has the payment term applied on the invoice Why the fix: ------------ Some modules needs
Original PR description
When you settle a sale order that has a payment term, it was always ignored in the PoS. But it should only be ignored when the payment term has an early discount. Steps to reproduce: ------------------- * Create a sale order with a payment term that has no early discount * Go to the PoS and settle the sale order * Invoice and validate the order > Observation: In the backend, the sale order has the payment term applied on the invoice Why the fix: ------------ Some modules needs the invoice to have payment terms set (l10n_mx for example). But the PoS invoice was always ignoring it. We should only ignore it if the payment terms has an early discount. opw-4670234 Forward-Port-Of: odoo/odoo#209999 Forward-Port-Of: odoo/odoo#207231
Originally, we compute rules for stock orderpoints based on product_id through `product_id._get_rules_from_location`, however, this function only relies on `product_id.route_ids` or `product_id.categ_id.total_route_ids` which usually don't change a lot per product. This PR leverages this idea that we can simply extend the caching key to include the routes_ids and categ_id.total_route_ids of products so we don't have to calculate the same value twice. For products without route_ids, it simply
Original PR description
Originally, we compute rules for stock orderpoints based on product_id through `product_id._get_rules_from_location`, however, this function only relies on `product_id.route_ids` or `product_id.categ_id.total_route_ids` which usually don't change a lot per product. This PR leverages this idea that we can simply extend the caching key to include the routes_ids and categ_id.total_route_ids of products so we don't have to calculate the same value twice. For products without route_ids, it simply falls back to the original cache key. Benchmarks |Num. orderpoints| Before PR | After PR | |---------------------|---------------|--------------| |5636| 56.2 s| 39.5 s| opw-4649249 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#202365
**[FIX] web_editor, website: prevent snippet tabs nav items removal** Steps to reproduce: 1. Go to Website edit mode. 2. Add a "Tabs" block. 3. Double-click a tab title to select it. 4. Start typing a new title. :white_check_mark: Expected: The tab title is replaced with the new text. :x: Actual: The tab is deleted and merged with the next one. This commit fixes the bug by preventing the deletion of elements with the `data-bs-toggle: 'tab'` attribute. These are clearly not eleme
Original PR description
**[FIX] web_editor, website: prevent snippet tabs nav items removal** Steps to reproduce: 1. Go to Website edit mode. 2. Add a "Tabs" block. 3. Double-click a tab title to select it. 4. Start typing a new title. :white_check_mark: Expected: The tab title is replaced with the new text. :x: Actual: The tab is deleted and merged with the next one. This commit fixes the bug by preventing the deletion of elements with the `data-bs-toggle: 'tab'` attribute. These are clearly not elements that an user should ever be allowed to delete. This commit also adds a test for the "Tab" snippet to prevent the bug from coming back. It also covers other flows that were previously known to be buggy in the "Tabs" snippet. opw-4791238 Forward-Port-Of: odoo/odoo#210187 Forward-Port-Of: odoo/odoo#209935
Versions -------- - 17.0+ Steps ----- 1. Create a coupon that grants a discount; 2. add a second reward giving free products; 3. use a product tag to turn it into a multiproduct reward; 4. save program, generate coupons, and copy a code; 5. add the free product tag to two or more products; 6. go to eCommerce; 7. add any product to cart and go to checkout; 8. apply coupon code; 9. claim a reward. Issue ----- - Claiming a free product results in a traceback. - Claiming the dis
Original PR description
Versions -------- - 17.0+ Steps ----- 1. Create a coupon that grants a discount; 2. add a second reward giving free products; 3. use a product tag to turn it into a multiproduct reward; 4. save…
Versions -------- - 17.0+ Steps ----- 1. Create a coupon that grants a discount; 2. add a second reward giving free products; 3. use a product tag to turn it into a multiproduct reward; 4. save program, generate coupons, and copy a code; 5. add the free product tag to two or more products; 6. go to eCommerce; 7. add any product to cart and go to checkout; 8. apply coupon code; 9. claim a reward. Issue ----- - Claiming a free product results in a traceback. - Claiming the discount does not apply the discount. Cause ----- Commit db3ffae3ef5a5 modified the reward claiming logic to allow for multiproduct rewards, but overlooked the possibility of the program having multiple rewards, multiproduct being one of them. It therefore passes all of the coupon's rewards to `_apply_reward`, which only expects a single reward. This is also a consequence of commit 6525d5fba40c, which moved part of the `claim_reward` logic to `pricelist`, without passing which reward was claimed to `pricelist`. Solution -------- Add an optional `reward_id` parameter to `pricelist`, letting it know which reward we intend to claim. opw-4778945 Forward-Port-Of: odoo/odoo#210214 Forward-Port-Of: odoo/odoo#209610
**Description of the issue/feature this PR addresses:** - The contact-us form allows task creation without a project (project_id = None). These tasks are assigned to odoobot, have no followers, and no project, making them inaccessible due to ACL restrictions. **steps to reproduce** 1. Install website_form_project. 2. Edit the contact-us form submit button. 3. Set action to 'Create a task' and select 'None' for the project. 4. Save and submit the form. **Observation** - Tasks creat
Original PR description
**Description of the issue/feature this PR addresses:** - The contact-us form allows task creation without a project (project_id = None). These tasks are assigned to odoobot, have no followers, and…
**Description of the issue/feature this PR addresses:** - The contact-us form allows task creation without a project (project_id = None). These tasks are assigned to odoobot, have no followers, and no project, making them inaccessible due to ACL restrictions. **steps to reproduce** 1. Install website_form_project. 2. Edit the contact-us form submit button. 3. Set action to 'Create a task' and select 'None' for the project. 4. Save and submit the form. **Observation** - Tasks created under such configuration are hidden in the UI and trigger access errors when trying to open them.  Desired behavior after PR is merged: - Making the project field required, the created tasks will now be accessible/visible [opw-4664601](https://www.odoo.com/odoo/project/49/tasks/4664601) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#207871
The `subscribe to known partner presences` test ensures that a bus subscription is sent when discovering a new partner whose presence needs tracking. However, the test triggers a channel join, which itself causes a bus subscription. Since both `add_channel` and `force_update_channels` are debounced, the outcome depends on which one executes first. As a result, `force_update_channels` may or may not include the newly added channel, making the test non-deterministic. In practice, this doesn'
Original PR description
The `subscribe to known partner presences` test ensures that a bus subscription is sent when discovering a new partner whose presence needs tracking. However, the test triggers a channel join, which itself causes a bus subscription. Since both `add_channel` and `force_update_channels` are debounced, the outcome depends on which one executes first. As a result, `force_update_channels` may or may not include the newly added channel, making the test non-deterministic. In practice, this doesn't matter: if `force_update_channels` omits the new channel, `add_channel` will later update the subscription as needed. This commit resolves the issue by ignoring `force_update_channels` in the test, since it's irrelevant in this context. fixes runbot-161223,182043,182044 Forward-Port-Of: odoo/odoo#210534
Steps to reproduce: - Install Stock and Field Service apps. - Create a product that tracks inventory by lot. - Add some on-hand quantity with a created lot. - In Field Service, create a task with `under_warranty` checked. - Add the created product to the task. Issue: - A sale order is generated with order lines at the product's price. - The price should be 0 since the customer should not be charged. Fix: - Ensure the sale order line price is set to 0 when `under_warranty` is checke
Original PR description
Steps to reproduce: - Install Stock and Field Service apps. - Create a product that tracks inventory by lot. - Add some on-hand quantity with a created lot. - In Field Service, create a task with `under_warranty` checked. - Add the created product to the task. Issue: - A sale order is generated with order lines at the product's price. - The price should be 0 since the customer should not be charged. Fix: - Ensure the sale order line price is set to 0 when `under_warranty` is checked in the _generate_lot() which is called on adding product tracked by lot. opw-4648542 opw-4646960 Forward-Port-Of: odoo/enterprise#82341
Currently, entering only spaces in the Full Name field when signing in auto mode enables the sign button, allowing users to proceed without a valid name. Steps to reproduce: 1. Sign > Create a request 2. Attempt to sign in auto mode with only spaces in the Full Name field 3. Observe that the sign button becomes enabled Cause: The system does not checks for whitespace-only name Solution: Add a validation to disable the sign button if the trimmed name is empty in auto mode. opw-462
Original PR description
Currently, entering only spaces in the Full Name field when signing in auto mode enables the sign button, allowing users to proceed without a valid name. Steps to reproduce: 1. Sign > Create a request 2. Attempt to sign in auto mode with only spaces in the Full Name field 3. Observe that the sign button becomes enabled Cause: The system does not checks for whitespace-only name Solution: Add a validation to disable the sign button if the trimmed name is empty in auto mode. opw-4628577 Forward-Port-Of: odoo/enterprise#85694 Forward-Port-Of: odoo/enterprise#84613
The xsd changed. Now the rounding needs to be to 2 decimals everywhere. The official xsd does not mention it, but the field submit_more must appear on the xml. Also, while it's not blocking directly, the declaration will be rejected if the special deduction is filled without specifying the special %age. So we add a banner warning the user of it. opw-4789154 Forward-Port-Of: odoo/enterprise#85593 Forward-Port-Of: odoo/enterprise#85464
Original PR description
The xsd changed. Now the rounding needs to be to 2 decimals everywhere. The official xsd does not mention it, but the field submit_more must appear on the xml. Also, while it's not blocking directly, the declaration will be rejected if the special deduction is filled without specifying the special %age. So we add a banner warning the user of it. opw-4789154 Forward-Port-Of: odoo/enterprise#85593 Forward-Port-Of: odoo/enterprise#85464
How to reproduce: - Install document in v17.0 with demo data - In the kanban view, upload an image in Marketing folder - The image is displayed as thumbnail in the kanban card - Upgrade to saas-17.4 - Open Document and go to marketing folder There is no thumbnail for the uploaded image. In v17, _compute_thumbnail_status write a False status when the thumbnail is updated because when it is trigerred the attachment is not yet created. So the thumbnail is present but its status is inco
Original PR description
How to reproduce: - Install document in v17.0 with demo data - In the kanban view, upload an image in Marketing folder - The image is displayed as thumbnail in the kanban card - Upgrade to saas-17.4…
How to reproduce: - Install document in v17.0 with demo data - In the kanban view, upload an image in Marketing folder - The image is displayed as thumbnail in the kanban card - Upgrade to saas-17.4 - Open Document and go to marketing folder There is no thumbnail for the uploaded image. In v17, _compute_thumbnail_status write a False status when the thumbnail is updated because when it is trigerred the attachment is not yet created. So the thumbnail is present but its status is incorrect. It works in v17 because the status is ignored by the view for images but in v17.4, the status is not ignored and the thumbnail is then not displayed. This temporary fix allows already migrated user to see thumbnail (as the view could not be modified in stable without an upgrade). We force the status of the thumbnail to "present" when there is no status for a thumbnail of an image which should cover the case where the status was not updated after the thumbnail creation. We have chosen this solution as the thumbnail will be updated in the upgrade and the URL returns anyway a placeholder image if the image is not present. We modify some tests to check that the patch is applied. As the kanban test data includes an image with a False status, the patch turns automatically the status to "present". So instead of having the generic mime type thumbnail, we get the actual thumbnail of the image. We change the assertions accordingly to test the new behavior and test the generic mime type thumbnail in the pdf case of the test "document inspector: document preview". Task-4642866 Forward-Port-Of: odoo/enterprise#81558
**Steps to reproduce:** - Install Planning app - Set the type of view to Gantt - (Create a shift if there is none) - Click on `Publish` button - The period end date doesn't take the last day into account (time is 00:00) **Issue:** Gantt model default `_buildMetaData` computation behavior was changed multiple times during previous refactoring: Previously used: ``` export function computeRange(scale, date) { let start = date; let end = date; if (scale === "week") {
Original PR description
**Steps to reproduce:** - Install Planning app - Set the type of view to Gantt - (Create a shift if there is none) - Click on `Publish` button - The period end date doesn't take the last day into…
**Steps to reproduce:**
- Install Planning app
- Set the type of view to Gantt
- (Create a shift if there is none)
- Click on `Publish` button
- The period end date doesn't take the last day into account (time is 00:00)
**Issue:**
Gantt model default `_buildMetaData` computation behavior was changed multiple times during previous refactoring:
Previously used:
```
export function computeRange(scale, date) {
let start = date;
let end = date;
if (scale === "week") {
// startOf("week") does not depend on locale and will always give the
// "Monday" of the week... (ISO standard)
const { weekStart } = localization;
const weekday = start.weekday < weekStart ? weekStart - 7 : weekStart;
start = start.set({ weekday }).startOf("day");
end = start.plus({ weeks: 1, days: -1 }).endOf("day");
} else {
start = start.startOf(scale);
end = end.endOf(scale);
}
return { start, end };
}
```
Which became:
```
export function getRangeFromDate(rangeId, date) {
const startDate = localStartOf(date, rangeId);
const stopDate = startDate.plus({ [rangeId]: 1 }).minus({ day: 1 });
return { focusDate: date, startDate, stopDate, rangeId };
}
```
**Fix:**
Added `localStartOf` function in the context setup of PlanningGanttModel.
To avoid overwriting current changes for other modules (which could be intended), this was done instead of :
```
export function getRangeFromDate(rangeId, date) {
const startDate = localStartOf(date, rangeId);
const stopDate = localEndOf(startDate, rangeId);
return { focusDate: date, startDate, stopDate, rangeId };
}
```
related commits:
https://github.com/odoo/enterprise/commit/d18639785e622d97102227103d62ddb3a2716be6 https://github.com/odoo/enterprise/commit/c175a848369057cc69596737dcd9d21dd24c9d5c
opw-4580458
Forward-Port-Of: odoo/enterprise#85608**Steps to reproduce:** 1. Install `website_sale_renting` 2. Go to the website editor. 3. Drag and drop the `rental search` snippet. 4. Set the rental timing to `hour` **Issue:** - The default date was always set to the next day with the current time, making it impossible for users to select the current date without adjusting the time manually. https://github.com/odoo/enterprise/blob/a6ec35e94bdd4f721982c32716f716948f74c875/website_sale_renting/static/src/js/website_sale_renting_dateran
Original PR description
**Steps to reproduce:** 1. Install `website_sale_renting` 2. Go to the website editor. 3. Drag and drop the `rental search` snippet. 4. Set the rental timing to `hour` **Issue:** - The default date was always set to the next day with the current time, making it impossible for users to select the current date without adjusting the time manually. https://github.com/odoo/enterprise/blob/a6ec35e94bdd4f721982c32716f716948f74c875/website_sale_renting/static/src/js/website_sale_renting_daterangepicker.js#L147-L148 **Solution:** - Updated the logic for hourly rentals to set the default date next day with adding one hour from the current time, to allow customers to select the current date. - For daily rentals, the logic remains unchanged and defaults to the next day. opw-4770823 Forward-Port-Of: odoo/enterprise#85613