Friday, September 5, 2025
13 changes · 18.0
Enhancements to existing features
Attendance approvers now get a read-only view in the Work Information section of My Profile when employees are not allowed to edit their own data. This keeps approval-related information visible while respecting company controls over employee profile edits.
Original PR description
Add read-only mode for the attendance approver in the My Profile Work Information tab when `allow employee to edit own data` is disabled. task-5008352 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The Budget Report now uses the analytic plan name, such as Project, instead of the generic label Account when grouping information. This makes the report easier for customers to understand and reduces confusion when reviewing budgets.
Original PR description
In this commit: - Change the group by label from `Account` to the analytic plan's name (`Project`) for clarity in the Budget Report. This improves customer understanding and reduces confusion. task-5045530
Resolved issues and error corrections
The Unsplash image search now handles duplicate images returned in the same search results. This prevents users from seeing an error when selecting images, such as during searches where Unsplash sends repeated results.
Original PR description
This commit fixes an OwlError when we try to render the images received from Unsplash after a search. The issue is that Unsplash can send duplicate images in the same batch of images. When we render those in a `t-foreach` and use the image `id`s as the keys, we get a duplicate key error. This is fixed by expanding on the previous filtering code, which ignored duplicates over multiple batches. We now ignore duplicates within batches as well. At the time of writing, Unsplash is sending us duplicate images on a search for "Inventory". opw-5027032 P.S., this is really just an extension of this PR here #224059. Specifically, the 18.0 FW. In 18.0, the Unsplash code that I changed in the original PR (#223789) was moved from `addons/web_unsplash/static/src/components/media_dialog/image_selector.js` to `(...)/components/media_dialog_legacy/image_selector.js`. This PR fixes the "copy" of that code that got moved.
Miscellaneous changes
Description of the issue/feature this PR addresses: - When a user cancels a filter on a burndown chart, if stageIdSearchItemId is undefined, an error is raised. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#197126 Forward-Port-Of: odoo/odoo#170510
Original PR description
Description of the issue/feature this PR addresses: - When a user cancels a filter on a burndown chart, if stageIdSearchItemId is undefined, an error is raised. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#197126 Forward-Port-Of: odoo/odoo#170510
Analytic line amounts now use the company currency rounding instead of the foreign currency rounding. This prevents misleading totals when foreign currencies have coarser rounding rules, improving accuracy for accounting review and reporting.
Original PR description
Steps to reproduce: - set the rounding of a foreign currency to 1.0 - have you company currency's rounding to 0.01 - create a move with a line with an analytic distribution - post it - go to analytic line Issue: The amount will be displayed with a rounding of 1.0 and not 0.01 opw-4997047
The Veri*Factu regime key dropdown on Spanish invoices now shows the expected options. This helps users complete compliant Spanish e-invoicing workflows without being blocked by an empty selection field.
Original PR description
### Issue: The dropdown for the regime key doesn't show any value, even when it's supposed to. ### Steps to reproduce: - Install "l10n_es_edi_verifactu" and switch to a Spanish company - Create an invoice for a Spanish partner with the tax "21% G (Goods)" for example - In the page "Veri*factu" the field "Veri*Factu Regime Key" has a dropdown but no values to choose from ### Cause: This field uses the widget `dynamic_selection` which applies a filter on the possible values of the selection. This filter is simply the field `l10n_es_edi_verifactu_available_clave_regimens` which is computed from the list of possible values and the tax_ids on the invoice. As this field is computed and non stored but do not appear in the view, it is never recomputed, so the dropdown shows no values. ### Solution: Add the field in the view, and make it invisible. opw-5039271
This fix ensures that when a customized view removes an element and adds text in the same area, the added text is correctly displayed. It prevents missing text in inherited templates when branding/debug metadata is enabled, improving reliability for customized Odoo screens.
Original PR description
With the inherit branding activated, have a xpath in an inherited view that removes a node, and adds some text afterwards in the parent of the removed node Before this commit, the text of the spec was not output. This was because it was appended to the removal ProcessingIntruction that was removed later on After this commit, a spec can add text in a node from which a child has been removed Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#223576
This fixes an error message that could fail when checking company compatibility on records linked to multiple companies. Users now receive a clear explanation of the incompatible company setup instead of a technical crash, helping them correct accounting or multi-company data issues faster.
Original PR description
`_check_company` can be called on models that don't have a `company_id` field, but they might have a `company_ids` one. In this case the message logged as the user error should be able to handle that…
`_check_company` can be called on models that don't have a `company_id` field, but they might have a `company_ids` one. In this case the message logged as the user error should be able to handle that scenario.
Example on how to reproduce the error in accounting:
```py
company_a, company_b
tax_group self.env["account.tax.group"].create(
{
"name": "Tax Group",
"company_id": company_a.id,
}
)
tax = self.env["account.tax"].create(
{
"name": "30% - Loan Tax",
"type_tax_use": "sale",
"tax_exigibility": "on_payment",
"amount": 30,
"amount_type": "percent",
"tax_group_id": tax_group.id,
"company_id": company_a.id,
}
)
account = self.env["account.account"].create({
...,
"company_ids": [Command.link(company_b.id)]
})
account.tax_ids |= tax
```
Error raised
```
AttributeError: 'account.account' object has no attribute 'company_id'
```
After the PR the following message appears:
```
odoo.exceptions.UserError: Incompatible companies on records:
- “Loan Principal” belongs to company “BE Company Loan Tests” and “Default Taxes” (tax_ids: '30% - Loan Tax') belongs to another company.
```
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#225177This fixes a rounding issue where loyalty discounts could use slightly more points than intended because of currency calculation precision. Customers and businesses now see loyalty point balances adjusted more accurately after sales orders are confirmed.
Original PR description
## Version
18.0+
## Issue
A slightly higher number of loyalty points might be used when python division can't be precise enough.
## Steps to reproduce
- Create a new Discount & Loyalty program:
- Program Type: Loyalty Cards;
- Conditional rules: None;
- Rewards: 1:
- Reward Type: Discount;
- Discount: 0.03$ per point on Order.
- Create a new Loyalty Card for any partner (remember which one):
- Change the points balance for 3030.
- Create a new Quotation for the previously selected partner as customer:
- Add a product:
- Use any product;
- Quantity: 1;
- Unit Price: 3000.0;
- Taxes: None.
- Apply the Reward and Confirm the SO;
- Check Loyalty Card's details at the bottom of the SO.
opw-4928963This fixes an error that could prevent gamification challenge report emails from being sent when some expected data was missing. The email template now handles missing values safely, improving reliability for users sending challenge reports.
Original PR description
If we use dict['foo'] in the template and that foo key does not exit, then a key error will be raised but if we use dict.get('foo'), then we can define which default value be returned whether None or ''.
Calling dict['foo'] or '' is no longer valid in python3.11, but better to use get method.
Steps to reproduce bug:
1: Create a challenge for gamification.challenge model
2: Set 'Display Mode': "Indiviual Goals"
3: Set any simple goal, set other required fields
4: Click on "Start Challenge" button
5: Click on "Send Report" button
Observation:
The mail xml template will fail to render and raise server error.
Solution:
Use get method to call the dictionary key value to safeguard.
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-prOdoo now handles missing SEPA pre-notification settings during module reinstallation, preventing an error when batch payments use SEPA Direct Debit. This keeps installation and reinstallation flows stable for companies using SEPA payment processing.
Original PR description
**Issue** When creating a batch payment with SEPA Direct Debit as payment method, if the user uninstalls the SEPA module and then installs it again, Odoo raises a `TypeError: 'int' object is not…
**Issue**
When creating a batch payment with SEPA Direct Debit as payment method, if the user uninstalls the SEPA module and then installs it again, Odoo raises a `TypeError: 'int' object is not iterable`.
**Steps to Reproduce**
1. Create a batch payment with SEPA Direct Debit.
2. Uninstall the `account_sepa_direct_debit` module.
3. Reinstall the module.
**Root Cause**
During module (re)installation, the compute method `_compute_sdd_required_collection_date` is triggered before any SEPA mandates or their pre-notification periods exist. This makes `mandates.mapped('pre_notification_period')` return an empty list. The code then calls:
max(minimum_offset, *mandates.mapped('pre_notification_period'))
When the list is empty, this reduces to `max(minimum_offset)`, which is invalid since `max()` with a single integer argument expects an iterable and raises a `TypeError`.
**Fix**
Handle the empty case so that there is a valid fallback both during installation and when mandates have no configured pre-notification period.
Opw-5042153Fixed an issue where adding many spreadsheet lists could cause related menu options to appear in the wrong place. This keeps spreadsheet menus organized and easier for users to navigate when working with many lists, pivots, or charts.
Original PR description
Steps to reproduce: - Add 25 lists in a spreadsheet => The order of the lists is not correct, menu items like "Re-insert static pivot" are positioned inside the list items. This commit fixes the sequence computation of the menu items for the pivots, lists and charts in spreadsheet to always be inside one integer (from 50 to 51 for pivots, 53 to 54 for lists, ...). Task: 5025230
Spreadsheet menus now keep list, pivot, and chart actions grouped in the correct order, even when many lists are added. This prevents unrelated actions from appearing in the middle of list entries, making the spreadsheet menu clearer and easier to use.
Original PR description
Steps to reproduce: - Add 25 lists in a spreadsheet => The order of the lists is not correct, menu items like "Re-insert static pivot" are positioned inside the list items. This commit fixes the sequence computation of the menu items for the pivots, lists and charts in spreadsheet to always be inside one integer (from 50 to 51 for pivots, 53 to 54 for lists, ...). Task: 5025230