Daily updates from Odoo
Navigate
Branch
Friday, August 14, 2026
284 changes
22 changes
Enhancements to existing features
Belgian payroll is updated to apply new fiscal employment bonus rates starting in August 2026 and future rate changes in 2028. This helps ensure payroll calculations remain aligned with upcoming Belgian tax rules for low-wage workers and general fiscal reductions.
Original PR description
Starting from August 2026: - The increased fiscal rate for low-wage workers (Volet B) rises from 52.54% to 63% (and to 72% in 2028). - The general fiscal rate (Volet A) rises from 33.14% to 35% starting in 2028. This adds new rule parameters for the fiscal rates and updates computation logic to apply these rates Task-6438319 Forward-Port-Of: odoo/enterprise#126713
Budget reports now load much faster for databases with many analytic lines and budget lines. The report matching logic was reorganized to avoid excessive comparisons, reducing a sample load time from nearly a minute to about one second.
Original PR description
**Description:** While loading the budget report, the bad queries are created by ```def _get_aal_query()``` and ```def _get_pol_query()``` function, makes the budget report unusable. **Root cause:**…
**Description:**
While loading the budget report, the bad queries are created by
```def _get_aal_query()``` and ```def _get_pol_query()``` function, makes
the budget report unusable.
**Root cause:**
Instead of doing a hash join while searching the record,
the OR statement in the Left Join in the condition
```(%(bl)s IS NULL OR %(a)s = %(bl)s)```
creates a nested for loop that compares everything single aal to bl,
this causes a significant performance issue as the number of the
number of check will be the the number aal * bl,
if a database has a 70k aal and 20k bl, both numbers are not large
but it will cause a 70k * 20k search which is more than a billion.
**Fix**:
There are some refactors made in this PR.
_First_, separate out the Q1.
In order to find the aal that has no bl connects to it.
Doing a search to find the aals that have bl and then subtract them from all aals.
_Second_, Instead of doing a nested loop for by using
```(%(bl)s IS NULL OR %(a)s = %(bl)s)```,
originally we will have do something like
```
JOIN budget_line bl
ON (bl.x_plan2_id IS NULL OR aal.x_plan2_id = bl.x_plan2_id)
AND (bl.x_plan3_id IS NULL OR aal.x_plan3_id = bl.x_plan3_id)
AND (bl.x_plan4_id IS NULL OR aal.x_plan4_id = bl.x_plan4_id)
```
Assuming each bl has three plans ```x_plan2_id```, ```x_plan3_id```, ```x_plan4_id```
Grouping the bl base on whether a specific plan is set, (i.e. shapes)
we can skip the ```IS NULL OR``` because we already know which plan
is null and do the hash join directly.
For example, the shapes will be a dictionary with a key of a tuple of booleans
based on whether a plan is set or not and the value is a list of bl_id.
```
{
(True, False, False): [1, 2],
(False, True, True): [3, 4],
(False, False, False): [5],
}
```
we can end up doing something like
```
JOIN budget_line bl
ON bl.id = ANY(ARRAY[3,4])
AND aal.x_plan3_id = bl.x_plan3_id AND aal.x_plan4_id = bl.x_plan4_id
```
which is way more faster.
---
The benchmark is made locally from this client's database which contains
69k aal, 23k bl, 6829 pol and 3 plans for aal and bl.
|Record count |Time before|Time after|
|--------------------------------------------------|-----------------|---------------|
|69k aal, 23k bl, 6829 pol, 3 plans |70.04s |4.6s |
Dalibo:
Before:
Month-over-month grand total by company:
https://explain.dalibo.com/plan/8h3d4e89aaf9f3d4
Overall grand total by company:
https://explain.dalibo.com/plan/445g1f9caf4923e2
Month-over-month grand total by plan:
https://explain.dalibo.com/plan/53a138ca50b2a7c4
Overall grand total by plan:
https://explain.dalibo.com/plan/hdbe169ddc7g5785
After:
Month-over-month grand total by company:
https://explain.dalibo.com/plan/hcc86c801e6872bf
Overall grand total by company:
https://explain.dalibo.com/plan/69b2421a3581f98h
Month-over-month grand total by plan:
https://explain.dalibo.com/plan/a88f398bbbch3148
Overall grand total by plan:
https://explain.dalibo.com/plan/1gg749ae7ab1553c
opw-6345552
Forward-Port-Of: odoo/enterprise#127732
Forward-Port-Of: odoo/enterprise#124161Timesheet Assistant suggestions are now easier to select in bulk by dragging across them with the mouse button held down. Ctrl-click no longer opens an unwanted new Odoo page, reducing accidental navigation and making batch actions faster.
Original PR description
Currently when the user uses ctrl + click on a suggestion, a new odoo page is opened. This is an undesirable side effect and it is removed in this commit. Also, users have to manually click on each suggestion when they want to remove them in batch, or create one timesheet for a bunch of suggestion. This commit lets user hover over suggestion with the mouse button pressed to select them. task-6385047 Forward-Port-Of: odoo/enterprise#124642
Only the person who created a signature request can now change a signer's email address. This helps prevent unintended or unauthorized recipient changes and improves trust in the signing process.
Original PR description
Forward-Port-Of: odoo/enterprise#127582 Forward-Port-Of: odoo/enterprise#126675
Spreadsheet pivots can now include SQL-based computed fields, giving users more flexible ways to analyze business data directly in spreadsheets. This improves reporting capabilities while keeping the change focused on the spreadsheet experience.
Original PR description
Task: 6442237 Forward-Port-Of: odoo/enterprise#126645
Resolved issues and error corrections
The attendance Gantt view now keeps today visible when users switch between time scales, such as week and day. This prevents the schedule from jumping away from the current day, making daily planning smoother and less confusing.
Original PR description
**Steps to Reproduce:** 1. Open attendnace Gantt view. 2. Set the scale to Week. 3. Set the scale back to Day. The view loses focus on today. **Reason:** * Before, when changing the scale on Gantt views and shrinking it, the view would always reset to today. * This behaviour was recently changed by the JS framework team to instead anchor the new time period around the date currently centered in the viewport. **Solution:** * If the current range includes today, scale while preserving today in the range. * Otherwise, keep the current behaviour and use the center of the viewport. Task: 6346363
Fixes an issue where enabling Equipment did not refresh linked stock lot information on draft field service planning shifts. This keeps equipment-related inventory details accurate after a recent internal status rename.
Original PR description
After odoo/enterprise#113153 renamed planning.slot states `draft` to `1_draft`, enabling Equipment no longer recomputed lot_ids on draft shifts because set_values/post_init still searched for state `draft`
Fixes an issue that prevented users from downloading the General Ledger report as a CSV when using French. The export now uses the correct translation context, so localized accounting reports download reliably instead of failing with an error.
Original PR description
Currently an exception is generated when the user tries to export (downlaod) a `CSV` file of the `General Ledger` report as the below step: - Install the `accountant` module with demo data - Enable…
Currently an exception is generated when the user tries to export (downlaod) a `CSV` file of the `General Ledger` report as the below step: - Install the `accountant` module with demo data - Enable and change to the `French` language - Go to `Comptabilité` > `Analyse` > `General Ledger` - Click the cog icon in the menu > Click on `CSV` - An error occurs in the log, and nothing is downloaded Error: `TypeError: 'NoneType' object is not subscriptable` This issue occurs after the recent refactoring changes in [1]. When `_generate_csv_lazy_export` is called, it uses the `_()` method for translation, which accesses `self.env`. However, at this point, the cursor is already closed. As a result, when the code at [2] is reached from `ormcache`, it raises the above error because `model.env.transaction.ormcaches__` is `None` (code ref [3]). This commit fixes the above issue by performing the translation using the existing `handler` variable, which contains an environment with the new cursor (see code ref [4]). [1]: https://github.com/odoo/odoo/commit/13c3adf3a8b5ba6325190d6b9aea45fb8a6a8b2f [2]: https://github.com/odoo/odoo/blob/5ef7829895b2e05650da394c1e35dfdc3a23c066/odoo/orm/cache.py#L111 [3]: https://github.com/odoo/odoo/blob/5ef7829895b2e05650da394c1e35dfdc3a23c066/odoo/orm/environments.py#L1012 [4]: https://github.com/odoo/enterprise/blob/912a47b8f0828ef8316b7e4ecdabf8a2f305b313/account_reports/models/account_general_ledger.py#L524 Sentry-7608119520
Australian Single Touch Payroll submissions now check that required payroll details are present before sending data to the ATO. Instead of a system traceback when an empty record is submitted, users receive a clear validation message so they can correct the record.
Original PR description
When submitting payroll data to the ATO from an STP record without any payslips or employees, a traceback is raised. Steps to reproduce the error: - Install ``l10n_au_hr_payroll_account`` module -…
When submitting payroll data to the ATO from an STP record without any payslips or employees, a traceback is raised. Steps to reproduce the error: - Install ``l10n_au_hr_payroll_account`` module - Switch to ``My australian Company`` - Go to Payroll > Configuration > Settings > In Australian Localization, Set BMS ID > Set STP Responsible and his date of birth - Go to Payroll > Reporting > Single Touch Payroll > Create a new record > Set Payment Date > Submit to ATO > Sign & Submit to ATO Traceback: ```py IndexError: tuple index out of range ``` https://github.com/odoo/enterprise/blob/b0e48baaf99bdc4faefd2ffdd3bd5637fb548593/l10n_au_hr_payroll_account/models/l10n_au_stp.py#L228-L233 The traceback occurs because ``_get_fiscal_year_start()`` assumes that the STP record always contains at least one payslip or one employee. When these recordsets are empty, indexing the first element raises an IndexError. Solution: This commit validates that the required payslips or employees are present before the submission and raises a validation error instead of a traceback. Forward-Port-Of: odoo/enterprise#127733 Forward-Port-Of: odoo/enterprise#124096
This fixes an automated payroll payrun test so it works reliably when confirming payruns and when country-specific payroll modules are installed. The change helps prevent false test failures without changing payroll behavior for end users.
Original PR description
This commit fixes a couple things with this tour: 1. We need to confirm the dialog that appears when we try to confirm the payrun itself 2. Depending on whether or not a particular l10n_XX module is…
This commit fixes a couple things with this tour:
1. We need to confirm the dialog that appears when we try to confirm the payrun itself
2. Depending on whether or not a particular l10n_XX module is installed, the trigger that we were previously using to check whether or not a payslip had been confirmed, `.btn[name='action_payment_report']` might not be there; i.e., l10n_us_hr_payroll, among others: https://github.com/odoo-dev/enterprise/blob/7767024956325d52fb30239967025b04999a9188/l10n_us_hr_payroll_account/views/hr_payslip_run_views.xml#L11-L13
It can be seen there ^ that that button is invisible under a slightly different condition than the base `hr_payroll` version of that button, causing an inconsistency in this test when that module is installed: https://github.com/odoo-dev/enterprise/blob/7767024956325d52fb30239967025b04999a9188/hr_payroll/vie
ws/hr_payslip_run_views.xml#L175
We resolve this by checking for either button in that step: `trigger: ".btn[name='action_paid'], .btn[name='action_payment_report']"`
runbot-243607Fixed an issue that caused audit report PDF exports from Accountant Knowledge to fail on systems using the newer PDF engine. Users can now generate these PDFs reliably, including on newer Python environments.
Original PR description
…ern pypdf backend `export_article_to_pdf` calls `writer.setPageMode("/UseOutlines")` on the `PdfFileWriter` instance to make the outline/bookmarks panel visible by default when the generated PDF is…
…ern pypdf backend
`export_article_to_pdf` calls `writer.setPageMode("/UseOutlines")` on the `PdfFileWriter` instance to make the outline/bookmarks panel visible by default when the generated PDF is opened. the old PyPDF2
`odoo.tools.pdf` picks its backend dynamically it first tries to import PyPDF2==2.12.1 and only falls back to the modern `pypdf` library if PyPDF2 is not importable, which is the case on Python 3.13 per requirements.txt, or on any worker where PyPDF2 failed to install.
The PyPDF2-based writer still exposes `setPageMode`, so the bug was never seen on backends using it. The modern pypdf-based writer replaced that method with a `page_mode` property (getter/setter) and never kept a camelCase alias for it
As a result, any request hitting this code got a beautiful HTTP 500
`AttributeError: 'BrandedFileWriter' object has no attribute 'setPageMode'`
`setPageMode` is not called anywhere else so
this fixes the call site directly instead of adding a new alias to the shared _pypdf.py
opw-6382905
Forward-Port-Of: odoo/enterprise#124480This fixes an issue in Odoo Sign where certain empty values could cause an error instead of being handled normally. Users should see fewer interruptions when preparing or processing signature requests with fields that do not have automatic values.
Original PR description
Forward-Port-Of: odoo/enterprise#127426
Fixes an issue where users without certain accounting permissions could be blocked from confirming sales orders when a Studio approval rule used a related accounting field. Approval checks now run with the necessary access so valid business workflows are not interrupted by unrelated permission limits.
Original PR description
continuation of [PR](https://github.com/odoo/enterprise/pull/121856) Issue: Inside _get_approval_spec filtered_domain is called a few times and due to a related field that calls an access rights group that the user who used the action isnt apart of is blocked by the filtered_domain. To Replicate: 1) Install studio, sale, Accounting and make sure "account_followup" is installed 2) create a related field on the sales.order form related to "customer -> follow up status" 3) Save 4) Create a "Studio Approval Rule" (studio.approval.rule) with a domain using the new related studio field -> method : "action_confirm" -> approver:admin 5)create a test user with no accounting access rights 6) in an incognito browser try and create a sales order, and then confirm it. it will throw the access rights error Solution: Go one up the stack where _get_approval_spec is called and add a syudo for those calls opw-6316069 Forward-Port-Of: odoo/enterprise#127412
Managers without full HR access can now launch appraisal campaigns for employees they oversee. The fix ensures selected employees are read correctly, preventing appraisals from being accidentally created for everyone when access rules hide the selection.
Original PR description
**Issue**: -User without hr rights is not allowed to launch campaigns for employees under him in the hierarchy. -This issue appears only in master, but it discovered another issue from 19.3, where the value for `employee_ids` was not accessed by the normal user. Thus, appraisals are created for all employees in the list, because not selecting an employee means selecting "All Employees". **Solution**: -SUDOing the read to allow the compute to see what the user has selected. Forward-Port-Of: odoo/enterprise#127391
When projects and tasks are created from templates, archived users are now excluded from task assignments linked to project roles. This prevents inactive employees or former team members from being assigned work through sales-created projects.
Original PR description
Steps to reproduce: ------------------------------------------------- 1. Install the `sale_project` module 2. Create a test user with Project User rights 3. Create a Project Role with the Created…
Steps to reproduce:
-------------------------------------------------
1. Install the `sale_project` module
2. Create a test user with Project User rights
3. Create a Project Role with the Created User as a Team Member
4. Create a Template Project as follows:
* Add one task to the template project
* Add the created Project role to the Task
5. Create a Service Type Product with:
* Create on order: Project
* Project Template: Created Template
6. Archive the Created User
7. Create and Confirm the Sale Order with the Created Product
Observation:
-------------------------------------------------
The generated task is assigned to the archived user, although the archived user is no longer part of the Project Role.
Issue:
-------------------------------------------------
While creating Project and Tasks from template, the context disable active record filtering (e.g., `active_test=False`), causing the assignment logic to fetch both active and inactive/archived users linked to the role. https://github.com/odoo/odoo/blob/8ec646e51497b38d34ea59296e0fc8644a50ee3a/odoo/orm/models.py#L4868
After that, during the `copy_data` method, It takes all the users from the roles without checking weather user is active or not
https://github.com/odoo/odoo/blob/8ec646e51497b38d34ea59296e0fc8644a50ee3a/addons/project/models/project_task.py#L890-L904
And even if we pass only Active users from this method, on moving further, it reassigns the users from roles without checking the Active field of the user
https://github.com/odoo/enterprise/blob/5abb147f9bf725daafc202d8259a5bb8a9b78d94/project_enterprise/models/project_task.py#L501-L503
https://github.com/odoo/enterprise/blob/5abb147f9bf725daafc202d8259a5bb8a9b78d94/project_enterprise/models/project_task.py#L544-L553
Due to this, the Archived User is also assigned to the tasks from the project roles
Solution:
-------------------------------------------------
Apply a `filtered('active')` check directly on the project role's users `(role.user_ids)` within the core task-copying logic in both `project` and `project_enterprise` modules. This ensures archived users are universally excluded from task assignments during template copying, regardless of what triggers the template instantiation.
Related Community PR: https://github.com/odoo/odoo/pull/274426
opw-6350841
Forward-Port-Of: odoo/enterprise#125637The Timesheet Assistant now recognizes time spent checking the Discuss inbox and labels the suggestion as "Checking Inbox". This replaces a confusing previous label, making timesheet suggestions easier for users to understand and confirm.
Original PR description
## Previous Behavior When the Timesheet Assistant detected a user spending time in their Discuss inbox, it generated a suggestion labeled "Discussing in/with Inbox". The name of this suggestion was judged to not make much sense. ## New Expected Behavior When the Timesheet Assistant detects a user spending time in their Discuss inbox, it will now generate a suggestion labeled "Checking Inbox" due to a new assistant rule. task-[6420655](https://www.odoo.com/odoo/project/4105/tasks/6420655) Forward-Port-Of: odoo/enterprise#126328
Planning managers without HR access can now change the resource on a planning slot without accidentally publishing it. The fix uses public employee information for the permission check, keeping planning updates aligned with the user's intended action.
Original PR description
For planning manager without HR access, if the user change the resource of the planning slot it will publish it automatically as the employee_ids field cannot be used without HR access. Prefer to use public employee to have better condition without using explicit sudo Caused-by: https://github.com/odoo/enterprise/commit/e88dcd0e545183b3f03e06b62158c52a1e6d2103 Forward-Port-Of: odoo/enterprise#127503
French VAT reimbursement declaration 3519 now includes the bank account holder name in the account details section. This helps meet required filing information and reduces the risk of rejected or incomplete reimbursement declarations.
Original PR description
For reimbursement declarations, the name of the holder of the account is required This commits adds holder's name to the account data zone no-task-id Forward-Port-Of: odoo/enterprise#127708 Forward-Port-Of: odoo/enterprise#127554
Payroll configuration now hides Mexico-specific CFDI settings when users are working in a non-Mexican company. This avoids confusion by showing these localization options only where they are relevant.
Original PR description
Steps to reproduce: 1. Switch to a non-Mexican company. 2. Go to Payroll > Configuration > Settings. 3. The CFDI settings block is visible. Reason: The CFDI block was missing a country check. Solution: Restrict the CFDI block visibility to Mexican companies. Task-6448440 Forward-Port-Of: odoo/enterprise#127022
The Timesheet Assistant now includes very small calendar events by adding their time to a matching larger event instead of ignoring them. This helps suggested timesheets reflect the full amount of time worked and reduces underreported totals.
Original PR description
## Previous Behavior Before this PR: When events were to small to suggestion Timesheet Assistant would completely discard these events. This lead to a suggestion haveing a lower total time than it should. ## New Expected Behavior After this PR: When an event is too small to suggest and shares its name and group with one or more larger event, the duration of the smaller event is added to the last event with the same name and groupe. task-[6452987](https://www.odoo.com/odoo/project/4105/tasks/6452987) Forward-Port-Of: odoo/enterprise#127167
The Point of Sale Urban Piper ticket screen now shows the order information button on mobile devices as well as desktop. This makes order details easier to access for staff using smaller screens, reducing friction during in-store or restaurant operations.
Original PR description
Before this commit: ------------ - The order info button was not visible on the ticket screen in the mobile UI. After this commit: ------------ - Display the order info button in both the mobile and desktop views of the ticket screen. Related: - Community: https://github.com/odoo/odoo/pull/276568 Task-6388045 Forward-Port-Of: odoo/enterprise#124485
This fix ensures signature fields stay in the correct visible position when signing PDFs that were created with unusual page origins. It prevents users from downloading signed documents where signatures or fields appear missing, improving reliability of the Sign workflow.
Original PR description
Steps to reproduce (version 16+): 1) Obtain a pdf with a negative origin point: This can occur when a customer exports a pdf from another software, or it can be made manually using a python script 2) In the sign app, upload the pdf and create a new template, add a signature field to the document. 3) Sign the document. The preview will load correctly and the signature will be visible 4) Download and open the signed pdf. The signature is not on the document Notes: Issue occurs because the signature was added to the pdf outside of the visible area. The preview works because the signature is rendered on top of the unsigned document in the correct location. The issue can be fixed applying a translation to the canvas. Ticket: [6317223](https://www.odoo.com/odoo/project/49/tasks/6317223?debug=assets) Forward-Port-Of: odoo/enterprise#127302 Forward-Port-Of: odoo/enterprise#121960
23 changes
Enhancements to existing features
The employee payroll review field now defaults to reviewed instead of an empty state. This removes ambiguity in employee records and helps payroll teams work with a clearer, consistent review status.
Original PR description
Default the field to '1_reviewed' task-6470096
The appointment booking view now groups entries by guest automatically. This makes it easier for staff to review bookings per customer and quickly understand guest activity without manually changing the view.
Original PR description
Add default Group By Guest Task-id: 6253719
Belgian payroll calculations now include upcoming fiscal employment bonus rate changes starting in August 2026 and 2028. This helps payroll teams apply the correct tax reductions for low-wage workers and general employment bonus cases as legal rates change.
Original PR description
Starting from August 2026: - The increased fiscal rate for low-wage workers (Volet B) rises from 52.54% to 63% (and to 72% in 2028). - The general fiscal rate (Volet A) rises from 33.14% to 35% starting in 2028. This adds new rule parameters for the fiscal rates and updates computation logic to apply these rates Task-6438319 Forward-Port-Of: odoo/enterprise#126713
Budget report loading has been optimized by changing how budget lines are matched and grouped during report generation. This reduces long waits on larger databases, improving usability for teams reviewing budgets and analytic costs.
Original PR description
**Description:** While loading the budget report, the bad queries are created by ```def _get_aal_query()``` and ```def _get_pol_query()``` function, makes the budget report unusable. **Root cause:**…
**Description:**
While loading the budget report, the bad queries are created by
```def _get_aal_query()``` and ```def _get_pol_query()``` function, makes
the budget report unusable.
**Root cause:**
Instead of doing a hash join while searching the record,
the OR statement in the Left Join in the condition
```(%(bl)s IS NULL OR %(a)s = %(bl)s)```
creates a nested for loop that compares everything single aal to bl,
this causes a significant performance issue as the number of the
number of check will be the the number aal * bl,
if a database has a 70k aal and 20k bl, both numbers are not large
but it will cause a 70k * 20k search which is more than a billion.
**Fix**:
There are some refactors made in this PR.
_First_, separate out the Q1.
In order to find the aal that has no bl connects to it.
Doing a search to find the aals that have bl and then subtract them from all aals.
_Second_, Instead of doing a nested loop for by using
```(%(bl)s IS NULL OR %(a)s = %(bl)s)```,
originally we will have do something like
```
JOIN budget_line bl
ON (bl.x_plan2_id IS NULL OR aal.x_plan2_id = bl.x_plan2_id)
AND (bl.x_plan3_id IS NULL OR aal.x_plan3_id = bl.x_plan3_id)
AND (bl.x_plan4_id IS NULL OR aal.x_plan4_id = bl.x_plan4_id)
```
Assuming each bl has three plans ```x_plan2_id```, ```x_plan3_id```, ```x_plan4_id```
Grouping the bl base on whether a specific plan is set, (i.e. shapes)
we can skip the ```IS NULL OR``` because we already know which plan
is null and do the hash join directly.
For example, the shapes will be a dictionary with a key of a tuple of booleans
based on whether a plan is set or not and the value is a list of bl_id.
```
{
(True, False, False): [1, 2],
(False, True, True): [3, 4],
(False, False, False): [5],
}
```
we can end up doing something like
```
JOIN budget_line bl
ON bl.id = ANY(ARRAY[3,4])
AND aal.x_plan3_id = bl.x_plan3_id AND aal.x_plan4_id = bl.x_plan4_id
```
which is way more faster.
---
The benchmark is made locally from this client's database which contains
69k aal, 23k bl, 6829 pol and 3 plans for aal and bl.
|Record count |Time before|Time after|
|--------------------------------------------------|-----------------|---------------|
|69k aal, 23k bl, 6829 pol, 3 plans |70.04s |4.6s |
Dalibo:
Before:
Month-over-month grand total by company:
https://explain.dalibo.com/plan/8h3d4e89aaf9f3d4
Overall grand total by company:
https://explain.dalibo.com/plan/445g1f9caf4923e2
Month-over-month grand total by plan:
https://explain.dalibo.com/plan/53a138ca50b2a7c4
Overall grand total by plan:
https://explain.dalibo.com/plan/hdbe169ddc7g5785
After:
Month-over-month grand total by company:
https://explain.dalibo.com/plan/hcc86c801e6872bf
Overall grand total by company:
https://explain.dalibo.com/plan/69b2421a3581f98h
Month-over-month grand total by plan:
https://explain.dalibo.com/plan/a88f398bbbch3148
Overall grand total by plan:
https://explain.dalibo.com/plan/1gg749ae7ab1553c
opw-6345552
Forward-Port-Of: odoo/enterprise#127581
Forward-Port-Of: odoo/enterprise#124161The timesheet assistant now shows the specific Odoo record name when ActivityWatch sees a recognizable page URL, instead of only showing the broader app name. This makes suggested work activities easier to understand and select, improving timesheet accuracy with minimal user disruption.
Original PR description
Before this commit, when the ActivityWatch integration encountered unmatched Odoo URLs, it would fallback to displaying the general application name (e.g., "Working on Sales"). With this commit, if the URL path ends with a valid record ID (e.g., /odoo/departments/1) and the corresponding model can be identified, the assistant will attempt to fetch and display the actual record name (e.g., "Working on Research & Development"). task: 6365568 Forward-Port-Of: odoo/enterprise#124138
Meal voucher reports now calculate the total voucher value correctly when vouchers are postponed. This helps Belgian payroll teams produce more accurate reporting and reduces the risk of incorrect employee benefit amounts.
Original PR description
-Adjust the total value for meal voucher report in case of postponed meal vouchers.
Spreadsheet pivot tables can now include calculated fields based on SQL data, making reports more flexible and useful for analysis. This improves spreadsheet reporting by allowing users to work with more derived business metrics directly in pivot views.
Original PR description
Task: 6442237 Forward-Port-Of: odoo/enterprise#126645
Only the person who created a signature request can now change a signer’s email address. This helps prevent unauthorized or accidental recipient changes, improving trust and control in the signing process.
Original PR description
Forward-Port-Of: odoo/enterprise#127582 Forward-Port-Of: odoo/enterprise#126675
Resolved issues and error corrections
Weekly rentals selected for exactly one week were sometimes counted as two weeks because default pickup and return times made the period slightly longer than seven days. The fix aligns those default times for weekly rentals so customers see the correct rental duration and price.
Original PR description
A product with a weekly rental periodicity is booked for 2 weeks when we actually book it for a single week Steps to reproduce: 1. Install Rental and eCommerce 2. Go to Rental > Products and create a new product 'test', in the Sales tab, set the rental periodicity to 'Weeks' 3. Click on the smart button 'Go to Website' 4. Change the rental period so that it exactly covers a week (e.g. from Monday to Monday) 5. The website shows that you're booking for 2 weeks Issue: The default pickup time is 9h and the default return time is 18h. When we select exactly one week for the rental duration, the true duration of the rental is greater than 1 week (because of the pickup and return time) so it is rounded as 2 weeks. Solution: Also swap `pickup_time` and `return_time` when swapping from weeks periodicity. opw-6397786
Fixes an issue that could prevent users from exporting audit report articles as PDFs in environments using the newer PDF processing backend. This restores reliable PDF export behavior and avoids server errors during a business reporting workflow.
Original PR description
…ern pypdf backend `export_article_to_pdf` calls `writer.setPageMode("/UseOutlines")` on the `PdfFileWriter` instance to make the outline/bookmarks panel visible by default when the generated PDF is…
…ern pypdf backend
`export_article_to_pdf` calls `writer.setPageMode("/UseOutlines")` on the `PdfFileWriter` instance to make the outline/bookmarks panel visible by default when the generated PDF is opened. the old PyPDF2
`odoo.tools.pdf` picks its backend dynamically it first tries to import PyPDF2==2.12.1 and only falls back to the modern `pypdf` library if PyPDF2 is not importable, which is the case on Python 3.13 per requirements.txt, or on any worker where PyPDF2 failed to install.
The PyPDF2-based writer still exposes `setPageMode`, so the bug was never seen on backends using it. The modern pypdf-based writer replaced that method with a `page_mode` property (getter/setter) and never kept a camelCase alias for it
As a result, any request hitting this code got a beautiful HTTP 500
`AttributeError: 'BrandedFileWriter' object has no attribute 'setPageMode'`
`setPageMode` is not called anywhere else so
this fixes the call site directly instead of adding a new alias to the shared _pypdf.py
opw-6382905Belgian point-of-sale self-orders are now signed using the designated self-ordering user, so mobile orders can be validated even when no cashier is logged in. This prevents fiscal device rejections and keeps self-order sales compliant while printing remains handled separately.
Original PR description
In this PR (github.com/odoo/enterprise/pull/126611) we removed the blackbox printingQueue, cause the pritning is now handled via Obox. - This commit reintroduce a signingQueue, but only for self-orders, as the printing is now handled via Obox. - It also fix the issue where signing a mobile self-order while no cashier is connected (login screen) was rejected by the FDM: signExternalOrder took the INSZ number from getCashier(), so signSale was sent without its required employeeId. - Self-orders are now signed with the INSZ number of the self-ordering default user, like the kiosk already does. FW of : https://github.com/odoo/enterprise/pull/126695
The Timesheet Assistant now recognizes time spent checking the Discuss inbox and labels the suggestion as “Checking Inbox.” This makes timesheet suggestions clearer and easier for users to understand.
Original PR description
## Previous Behavior When the Timesheet Assistant detected a user spending time in their Discuss inbox, it generated a suggestion labeled "Discussing in/with Inbox". The name of this suggestion was judged to not make much sense. ## New Expected Behavior When the Timesheet Assistant detects a user spending time in their Discuss inbox, it will now generate a suggestion labeled "Checking Inbox" due to a new assistant rule. task-[6420655](https://www.odoo.com/odoo/project/4105/tasks/6420655)
Creating an employee declaration without selecting an employee no longer triggers an application error. This prevents an avoidable interruption in Belgian payroll reporting and makes the declaration workflow more reliable.
Original PR description
When creating an employee declaration without selecting an employee, a traceback occurs. Steps to reproduce the error: - Install ``l10n_be_hr_payroll`` module with demo data - Switch to Belgian…
When creating an employee declaration without selecting an employee, a traceback occurs. Steps to reproduce the error: - Install ``l10n_be_hr_payroll`` module with demo data - Switch to Belgian company - Go to Payroll > Reporting > Individual Accounts > Create a new Individual Account > Click on Eligible Employees > Create a new employee declaration without employee > Save Traceback: ```py ValueError: Expected singleton: hr.employee() ``` https://github.com/odoo/enterprise/blob/000544c3d5b93e194264e15bb73d9599525106e3/hr_payroll/models/hr_payroll_employee_declaration.py#L71 The ``_compute_version_id()`` method calls ``_get_version()``. When ``employee_id`` is empty, ``_get_version()`` is invoked on an empty ``hr.employee`` record, and its ``ensure_one()`` call raises the above traceback at [1]. [1]: https://github.com/odoo/odoo/blob/3c358ae2badad69b125695a97b4a14e8ab77fccd/addons/hr/models/hr_employee.py#L745-L750 sentry-7625826444 Forward-Port-Of: odoo/enterprise#125175
Spanish VAT record book exports now work for accounting users even when the report includes Point of Sale data. This prevents access errors during tax reporting while keeping the POS data use limited to building the report.
Original PR description
Steps to reproduce:
- With an ES Company
- Open a POS session, add product with tax and pay
- As a user with only accounting access
- Go to Accouting > Reporting > Tax report
- Select Generic Tax report
- Print "VAT record Books"
Issue:
An AccessError will raise
```
Access Error
You are not allowed to access 'Point of Sale Session' (pos.session) records.
This operation is allowed for the following groups:
- Point of Sale/User
Contact your administrator to request access if necessary.
```
Analysis:
Vat Record Books handler for POS needs to read pos.session and pos.order records. Currently, the action is performed with the rights of the user running the report, so accounting-only user face an error.
As POS records are only read internally to build the report, we add sudo call to get the data.
opw-5862529
Forward-Port-Of: odoo/enterprise#126590
Forward-Port-Of: odoo/enterprise#125980French VAT reimbursement declaration 3519 now includes the bank account holder's name in the account details section. This helps meet filing requirements and reduces the risk of rejected or incomplete reimbursement declarations.
Original PR description
For reimbursement declarations, the name of the holder of the account is required This commits adds holder's name to the account data zone no-task-id Forward-Port-Of: odoo/enterprise#127708 Forward-Port-Of: odoo/enterprise#127554
The Timesheet Assistant no longer drops very short calendar events when building time suggestions. If a short event matches a larger event by name and group, its time is added to the related suggestion so totals are more accurate.
Original PR description
## Previous Behavior Before this PR: When events were to small to suggestion Timesheet Assistant would completely discard these events. This lead to a suggestion haveing a lower total time than it should. ## New Expected Behavior After this PR: When an event is too small to suggest and shares its name and group with one or more larger event, the duration of the smaller event is added to the last event with the same name and groupe. task-[6452987](https://www.odoo.com/odoo/project/4105/tasks/6452987)
Managers without HR permissions can now launch appraisal campaigns for employees they manage. The fix also prevents campaigns from accidentally applying to all employees when selected employee records were not readable by the user.
Original PR description
**Issue**: -User without hr rights is not allowed to launch campaigns for employees under him in the hierarchy. -This issue appears only in master, but it discovered another issue from 19.3, where the value for `employee_ids` was not accessed by the normal user. Thus, appraisals are created for all employees in the list, because not selecting an employee means selecting "All Employees". **Solution**: -SUDOing the read to allow the compute to see what the user has selected.
This fixes an issue where users without Accounting permissions could be blocked from confirming sales orders when a Studio approval rule used certain customer follow-up fields. Approval checks now run with the right elevated access so normal business workflows are not interrupted by unrelated permission limits.
Original PR description
continuation of [PR](https://github.com/odoo/enterprise/pull/121856) Issue: Inside _get_approval_spec filtered_domain is called a few times and due to a related field that calls an access rights group that the user who used the action isnt apart of is blocked by the filtered_domain. To Replicate: 1) Install studio, sale, Accounting and make sure "account_followup" is installed 2) create a related field on the sales.order form related to "customer -> follow up status" 3) Save 4) Create a "Studio Approval Rule" (studio.approval.rule) with a domain using the new related studio field -> method : "action_confirm" -> approver:admin 5)create a test user with no accounting access rights 6) in an incognito browser try and create a sales order, and then confirm it. it will throw the access rights error Solution: Go one up the stack where _get_approval_spec is called and add a syudo for those calls opw-6316069 Forward-Port-Of: odoo/enterprise#127412
Recruitment officers without payroll permissions can now generate and open Belgian salary offers without running into an access error. This fixes a workflow blocker caused by a payroll-related warning check that used information recruiters are not allowed to read directly.
Original PR description
The field `hr.contract.salary.offer.l10n_be_is_below_scale_warning` is accessible to users outside of the payroll groups but its computation requires a read access to payroll only fields on the related `hr.version`. Steps to reproduce: 1- log in with a user that has the group Recruitment/ Officer, and no payroll privileges. 2- go to an applicant and click generate offer 3- The offer will be created but the user will not have access to it and the redirection will fail reported by our recruitment officers
Submitting Australian Single Touch Payroll records without payslips or employees now shows a clear validation message instead of causing an unexpected error. This helps payroll users understand what information is missing before sending data to the ATO.
Original PR description
When submitting payroll data to the ATO from an STP record without any payslips or employees, a traceback is raised. Steps to reproduce the error: - Install ``l10n_au_hr_payroll_account`` module -…
When submitting payroll data to the ATO from an STP record without any payslips or employees, a traceback is raised. Steps to reproduce the error: - Install ``l10n_au_hr_payroll_account`` module - Switch to ``My australian Company`` - Go to Payroll > Configuration > Settings > In Australian Localization, Set BMS ID > Set STP Responsible and his date of birth - Go to Payroll > Reporting > Single Touch Payroll > Create a new record > Set Payment Date > Submit to ATO > Sign & Submit to ATO Traceback: ```py IndexError: tuple index out of range ``` https://github.com/odoo/enterprise/blob/b0e48baaf99bdc4faefd2ffdd3bd5637fb548593/l10n_au_hr_payroll_account/models/l10n_au_stp.py#L228-L233 The traceback occurs because ``_get_fiscal_year_start()`` assumes that the STP record always contains at least one payslip or one employee. When these recordsets are empty, indexing the first element raises an IndexError. Solution: This commit validates that the required payslips or employees are present before the submission and raises a validation error instead of a traceback. Forward-Port-Of: odoo/enterprise#127733 Forward-Port-Of: odoo/enterprise#124096
WhatsApp channel members can once again access Advanced Settings to manage membership. This fixes a regression in version 19.3 where the option was hidden, preserving a familiar and more suitable workflow for WhatsApp channels.
Original PR description
Show the advanced-settings thread action for WhatsApp channel members, since channel_role is only supported on channel/group types which controls this button. Advanced Settings have long been used to manage channel membership. Their removal in 19.3+ introduced a regression, while channel roles are more cumbersome and do not integrate well with WhatsApp concern similarly to livechat: https://github.com/odoo/enterprise/pull/112959#discussion_r3593831089. so keeping Advanced Settings for WhatsApp for now.
Payroll configuration now only shows Mexico-specific CFDI settings when the active company is based in Mexico. This prevents irrelevant tax invoicing options from appearing for companies in other countries, reducing confusion during setup.
Original PR description
Steps to reproduce: 1. Switch to a non-Mexican company. 2. Go to Payroll > Configuration > Settings. 3. The CFDI settings block is visible. Reason: The CFDI block was missing a country check. Solution: Restrict the CFDI block visibility to Mexican companies. Task-6448440 Forward-Port-Of: odoo/enterprise#127022
This fix prevents batch invoice sending to SUNAT from being blocked when some Peruvian invoices contain lines without taxes. Instead of a generic technical failure, the system handles the issue consistently with single-invoice sending so other invoices can continue processing.
Original PR description
In l10n_pe_edi, invoices containing lines without tax can't be submitted to SUNAT.
When sending a single invoice, an error message is displayed. However, sending multiple invoices processes them in the background by a cron job. In this case, EDI document creation fails without error handling, raising a generic parsing error and blocking the cron from processing other invoices.
Steps to reproduce:
1. Create and post two invoices with no tax on some lines.
2. From the list view, select both invoices and click "Send" and mark "SUNAT".
3. An exception is raised: `ValueError: XMLSyntaxError("Start tag expected, '<' not found, line 1, column 1")`.
opw-6390480
Forward-Port-Of: odoo/enterprise#12514314 changes
Resolved issues and error corrections
This fix adjusts an internal Belgian payroll test so it uses a normal working day instead of a Sunday. It prevents false test failures during leave validation, helping keep payroll maintenance and releases reliable without changing user-facing behavior.
Original PR description
The test `test_float_holiday_attest` fails with a ValidationError: "The following employees are not supposed to work during that period". The previous patch (cf. PR odoo/enterprise#107490) froze time to "2026-02-01 08:00:00", which was a Sunday. When validating the leave created for `today`, check of the employee's calendar fails because zero working hours are scheduled on weekends. This commit updates `@freeze_time` to "2026-02-02 08:00:00" (Monday) so the leave validation runs against a valid working day. runbot-240132 runbot-241193 Forward-Port-Of: odoo/enterprise#126391
French VAT reimbursement declarations now include the bank account holder's name in the account details section. This helps ensure declaration 3519 contains all required account information and reduces the risk of rejected or incomplete refund submissions.
Original PR description
For reimbursement declarations, the name of the holder of the account is required This commits adds holder's name to the account data zone no-task-id Forward-Port-Of: odoo/enterprise#127631 Forward-Port-Of: odoo/enterprise#127554
Barcode receipts now keep the putaway destination when users scan multiple lots for the same product. This prevents items from being split between the intended shelf and the default stock location, reducing warehouse confusion and manual corrections.
Original PR description
Steps to reproduce --- 1. Enable Storage Locations and Lots & Serial Numbers. 2. Add a putaway rule sending a lot-tracked product from WH/Stock to WH/Stock/Shelf 1. 3. Confirm a receipt reserving 2…
Steps to reproduce --- 1. Enable Storage Locations and Lots & Serial Numbers. 2. Add a putaway rule sending a lot-tracked product from WH/Stock to WH/Stock/Shelf 1. 3. Confirm a receipt reserving 2 units of that product; putaway sets the reserved move line destination to WH/Stock/Shelf 1. 4. In the Barcode app, scan a first lot, then a second lot. The second lot lands on a separate line at WH/Stock instead of WH/Stock/Shelf 1. Issue --- The first lot reuses the reserved line and keeps its Shelf 1 destination. The second lot cannot reuse it because its tracking number differs, so `_findLine` returns nothing and `_getNewLineDefaultValues` builds a new line with `location_dest_id` set to `_defaultDestLocation()`, the picking's default destination (WH/Stock). https://github.com/odoo/enterprise/blob/314a79b774f30dc9377b2971492576c4b84483e1/stock_barcode/static/src/models/barcode_picking_model.js#L1591-L1601 Putaway relocates the destination on the move line at reservation, never on the picking, so only the reserved line carries Shelf 1. Since `groupKey` includes `location_dest_id`, the new line does not group with the first lot and shows separately at WH/Stock. This is not a regression: new lines have always defaulted to the operation destination. https://github.com/odoo/enterprise/blob/314a79b774f30dc9377b2971492576c4b84483e1/stock_barcode/static/src/models/barcode_picking_model.js#L239-L241 The new line now inherits the selected line's `location_dest_id`, already relocated by putaway, instead of the default. opw-6317077 Forward-Port-Of: odoo/enterprise#125309
The Helpdesk Stock ticket screen now shows the Replace button even when no customer is selected. This keeps the action available in the same way as related buttons, reducing confusion for support teams handling stock-related helpdesk cases.
Original PR description
Adjust the `invisible` condition to make the button visible even if no customer is selected, for consistency with other buttons --- task-6103996 Forward-Port-Of: odoo/enterprise#124467
This fixes an issue where financial reports could show incorrect date ranges after switching between companies with different fiscal year setups. The report now selects the correct fiscal year based on the chosen end date, helping keep period-based reporting accurate.
Original PR description
Fix year-mode date filter when switching between companies with different fiscal years With two companies configured: one using a standard fiscal year and one using an offset fiscal year, switching between them could produce incorrect date ranges. This happened because the previous company’s `date_to` value was reused to compute the current period for the newly selected company, and vice versa. The fix is to use the `date_to` year instead and select the latest fiscal year ending in that same year.
Invoices in Peru that include lines without taxes now fail with a clear, handled message during batch sending instead of causing a generic system error. This prevents the background sending process from getting blocked and allows other invoices to continue being processed.
Original PR description
In l10n_pe_edi, invoices containing lines without tax can't be submitted to SUNAT.
When sending a single invoice, an error message is displayed. However, sending multiple invoices processes them in the background by a cron job. In this case, EDI document creation fails without error handling, raising a generic parsing error and blocking the cron from processing other invoices.
Steps to reproduce:
1. Create and post two invoices with no tax on some lines.
2. From the list view, select both invoices and click "Send" and mark "SUNAT".
3. An exception is raised: `ValueError: XMLSyntaxError("Start tag expected, '<' not found, line 1, column 1")`.
opw-6390480An automated accounting test was adjusted to match a related platform change in how grouped data is read. This keeps the accounting test suite aligned with the updated behavior and helps prevent false test failures during releases.
Original PR description
The fix at https://github.com/odoo/odoo/pull/281911 adds bin_size: tru in the web_read_group. This commit adpats an accounting test as a consequence Forward-Port-Of: odoo/enterprise#127638
The timesheet assistant layout now keeps duration values on one line, adds spacing, and allows long titles to wrap cleanly. This prevents overlapping text in chronological views, making timesheet entries easier to read and review.
Original PR description
- enforce duration in one line - add a gap between the title and duration - wrap title if so long - adapt flex direction of chronological view to avoid overlapping of title and start time --- task-6432434
This fix corrects how certain Swiss payroll tax mutation values are listed in declarations. It helps ensure submitted payroll information uses the expected official format, reducing the risk of reporting errors or follow-up corrections.
Original PR description
task-6116327 Forward-Port-Of: odoo/enterprise#127745
The timesheet assistant now preserves a project chosen by the user when switching between suggestions. This prevents accidental replacement of an unsaved project selection, reducing data entry mistakes and rework.
Original PR description
Steps to reproduce: - Select an unmatched suggestion. - Select Project A on the timesheet form (do not save it yet). - Select another suggestion matched to Project B. Observed behavior: Project A is overridden by Project B. Expected behavior: Project A remains selected on the timesheet. By initializing `project_id` with the current record's data, we prevent the suggestion loop from overwriting the user's manual selection. task-6410844 Forward-Port-Of: odoo/enterprise#126450
Fixed an issue that caused Deferred Revenue Report exports to fail when the report included annotations. Business users can now export annotated accounting reports to Excel without encountering a server error.
Original PR description
**Steps to reproduce:** * Install the **Accounting** module. * Unhide the **Start Date** and **End Date** fields on invoice lines. * Create and post a customer invoice with deferred dates. * Go to…
**Steps to reproduce:** * Install the **Accounting** module. * Unhide the **Start Date** and **End Date** fields on invoice lines. * Create and post a customer invoice with deferred dates. * Go to **Accounting → Reports → Deferred Revenue Report**. * Add an annotation to a deferred revenue line by clicking the **annotate** from three dots next to the account. * Export the report in **XLSX** format. **Observed behavior:** * The export fails with a server error: `UnboundLocalError: cannot access local variable 'annotations_x_offset' where it is not associated with a value` **Cause:** * The variable `annotations_x_offset` is assigned inside the `for header_level_index, header_level in enumerate(options['column_headers'])` loop, which writes the "Annotations" column header for each header level. * The Deferred Revenue Report produces an empty `column_headers` list, so the loop body never executes and `annotations_x_offset` is never assigned. * When the code later tries to write annotation data for each report line, it references the unassigned variable, causing Python to raise `UnboundLocalError`. **Fix:** * Introduce a boolean flag `annotations_header_written = False` before the header loop to explicitly track whether the "Annotations" column header has already been written. * Inside the header loop, set `annotations_header_written = True` after writing the header. * After writing all individual column headers (where `x_offset` already points to the first free column after all data columns), add a fallback: if `report_annotations` is set but `annotations_header_written` is still `False`, assign `annotations_x_offset` from the current `x_offset` and write the "Annotations" header. opw-6354473 Forward-Port-Of: odoo/enterprise#127726 Forward-Port-Of: odoo/enterprise#122768
Accounting users can now export Spanish VAT record books even when the report includes Point of Sale transactions. The report safely reads the needed POS data internally, preventing access errors while keeping normal user permissions unchanged.
Original PR description
Steps to reproduce:
- With an ES Company
- Open a POS session, add product with tax and pay
- As a user with only accounting access
- Go to Accouting > Reporting > Tax report
- Select Generic Tax report
- Print "VAT record Books"
Issue:
An AccessError will raise
```
Access Error
You are not allowed to access 'Point of Sale Session' (pos.session) records.
This operation is allowed for the following groups:
- Point of Sale/User
Contact your administrator to request access if necessary.
```
Analysis:
Vat Record Books handler for POS needs to read pos.session and pos.order records. Currently, the action is performed with the rights of the user running the report, so accounting-only user face an error.
As POS records are only read internally to build the report, we add sudo call to get the data.
opw-5862529
Forward-Port-Of: odoo/enterprise#126590
Forward-Port-Of: odoo/enterprise#125980Rejection notification emails now show the name of the person who declined to sign, rather than the email recipient's name. This prevents confusion for other parties involved in the signing process and makes document status updates more accurate.
Original PR description
**Description of the issue/feature this PR addresses:** When a document is rejected by a signer, the notification email sent to other involved parties incorrectly displays the recipient's name in the…
**Description of the issue/feature this PR addresses:** When a document is rejected by a signer, the notification email sent to other involved parties incorrectly displays the recipient's name in the subject line instead of the person who actually refused to sign. This occurs because the subject string was using `partner.name` (the current email recipient) instead of `refuser.name`. This commit updates the string to reference the refuser, ensuring the subject accurately identifies the individual who rejected the document. **Steps to reproduce:** - Sign > upload any PDF > add signature request for 2 different signers > Send > choose signers, e.g. Abigail Carter and Marc Demo > Send - Settings > Technical > Emails > Emails - Select one of the sent emails > Sign document > sign > Validate & Send Completed Document - Select the other email > Sign document > top-right dropdown arrow > Decline to sign > Decline - Settings > Technical > Emails > Emails - Observe that all emails sent state that the recipient of the email rejected the signing **Current behavior before PR:** - Rejection email subject states that the recipient refused to sign **Desired behavior after PR is merged:** - Rejection email subject states that the refuser refused to sign opw-6421188 Forward-Port-Of: odoo/enterprise#126412
Australian payroll submissions now check that required payslip or employee information exists before sending data to the ATO. Instead of an unexpected system error, users receive a clear validation message, helping payroll teams correct incomplete STP records more easily.
Original PR description
When submitting payroll data to the ATO from an STP record without any payslips or employees, a traceback is raised. Steps to reproduce the error: - Install ``l10n_au_hr_payroll_account`` module -…
When submitting payroll data to the ATO from an STP record without any payslips or employees, a traceback is raised. Steps to reproduce the error: - Install ``l10n_au_hr_payroll_account`` module - Switch to ``My australian Company`` - Go to Payroll > Configuration > Settings > In Australian Localization, Set BMS ID > Set STP Responsible and his date of birth - Go to Payroll > Reporting > Single Touch Payroll > Create a new record > Set Payment Date > Submit to ATO > Sign & Submit to ATO Traceback: ```py IndexError: tuple index out of range ``` https://github.com/odoo/enterprise/blob/b0e48baaf99bdc4faefd2ffdd3bd5637fb548593/l10n_au_hr_payroll_account/models/l10n_au_stp.py#L228-L233 The traceback occurs because ``_get_fiscal_year_start()`` assumes that the STP record always contains at least one payslip or one employee. When these recordsets are empty, indexing the first element raises an IndexError. Solution: This commit validates that the required payslips or employees are present before the submission and raises a validation error instead of a traceback. Forward-Port-Of: odoo/enterprise#127733 Forward-Port-Of: odoo/enterprise#124096
9 changes
Security fixes and vulnerability patches
Odoo Sign now verifies that a user can read a record before allowing it to be linked to a signature request. This prevents users from exposing information from records they are not authorized to access by manually changing the linked record.
Original PR description
Version: saas-18.3 Reported issue: 1. Marc Demo creates a sign request from a template whose fields are automatically populated from the linked record. 2. It is sent to himself. He does not have…
Version: saas-18.3 Reported issue: 1. Marc Demo creates a sign request from a template whose fields are automatically populated from the linked record. 2. It is sent to himself. He does not have access to all records of a referenced model (e.g. Sales Orders). 3. The "Linked To" (reference_doc) field is edited afterwards to point to a record the signer does not have access to. By the time it's signed, the value of that record becomes visible - so a user can, simply by changing the linked record, see the value of a record they were never authorized to access. Even a Sign Manager could link a request to a record they have no access to and later see its value through it. Issue: `reference_doc` could be set or changed to any record of any allowed model with no validation that the acting user actually has access to it. In the interface, you can only create a signature request from a record you can see, but editing `reference_doc` manually (via write(), RPC, etc.) was not held to the same rule, making it an easy way to leak information about records outside your normal access. Cause: The only restriction was cosmetic, enforced client-side by the record picker widget filtering its search results. Nothing on the server validated the value being written to `reference_doc`. Fix: `write()` now checks that the acting user has read access to the target record before allowing `reference_doc` to be set, raising a ValidationError otherwise, bringing manual edits in line with what the interface already enforces when creating a request. Forward-Port-Of: odoo/enterprise#127715
Enhancements to existing features
Spreadsheet pivot tables can now include SQL-based computed fields, giving users more ways to build custom analyses directly in spreadsheets. This improves reporting flexibility and helps teams extract more tailored insights without leaving the spreadsheet workflow.
Original PR description
Task: 6442237
Odoo Sign now limits changes to a signer's email address to the person who created the signing request. This helps prevent unintended or unauthorized recipient changes, improving control over who receives and signs documents.
Original PR description
Forward-Port-Of: odoo/enterprise#127582 Forward-Port-Of: odoo/enterprise#126675
Resolved issues and error corrections
Annotated Deferred Revenue Reports can now be exported to Excel without triggering a server error. This helps accounting users reliably download reports even when the report has annotations and no standard column headers.
Original PR description
**Steps to reproduce:** * Install the **Accounting** module. * Unhide the **Start Date** and **End Date** fields on invoice lines. * Create and post a customer invoice with deferred dates. * Go to…
**Steps to reproduce:** * Install the **Accounting** module. * Unhide the **Start Date** and **End Date** fields on invoice lines. * Create and post a customer invoice with deferred dates. * Go to **Accounting → Reports → Deferred Revenue Report**. * Add an annotation to a deferred revenue line by clicking the **annotate** from three dots next to the account. * Export the report in **XLSX** format. **Observed behavior:** * The export fails with a server error: `UnboundLocalError: cannot access local variable 'annotations_x_offset' where it is not associated with a value` **Cause:** * The variable `annotations_x_offset` is assigned inside the `for header_level_index, header_level in enumerate(options['column_headers'])` loop, which writes the "Annotations" column header for each header level. * The Deferred Revenue Report produces an empty `column_headers` list, so the loop body never executes and `annotations_x_offset` is never assigned. * When the code later tries to write annotation data for each report line, it references the unassigned variable, causing Python to raise `UnboundLocalError`. **Fix:** * Introduce a boolean flag `annotations_header_written = False` before the header loop to explicitly track whether the "Annotations" column header has already been written. * Inside the header loop, set `annotations_header_written = True` after writing the header. * After writing all individual column headers (where `x_offset` already points to the first free column after all data columns), add a fallback: if `report_annotations` is set but `annotations_header_written` is still `False`, assign `annotations_x_offset` from the current `x_offset` and write the "Annotations" header. opw-6354473 Forward-Port-Of: odoo/enterprise#127726 Forward-Port-Of: odoo/enterprise#122768
Australian payroll submissions to the ATO now check that required payslip or employee data is present before submission. Instead of an unexpected system error, users receive a clear validation message, helping payroll teams correct the issue and continue safely.
Original PR description
When submitting payroll data to the ATO from an STP record without any payslips or employees, a traceback is raised. Steps to reproduce the error: - Install ``l10n_au_hr_payroll_account`` module -…
When submitting payroll data to the ATO from an STP record without any payslips or employees, a traceback is raised. Steps to reproduce the error: - Install ``l10n_au_hr_payroll_account`` module - Switch to ``My australian Company`` - Go to Payroll > Configuration > Settings > In Australian Localization, Set BMS ID > Set STP Responsible and his date of birth - Go to Payroll > Reporting > Single Touch Payroll > Create a new record > Set Payment Date > Submit to ATO > Sign & Submit to ATO Traceback: ```py IndexError: tuple index out of range ``` https://github.com/odoo/enterprise/blob/b0e48baaf99bdc4faefd2ffdd3bd5637fb548593/l10n_au_hr_payroll_account/models/l10n_au_stp.py#L228-L233 The traceback occurs because ``_get_fiscal_year_start()`` assumes that the STP record always contains at least one payslip or one employee. When these recordsets are empty, indexing the first element raises an IndexError. Solution: This commit validates that the required payslips or employees are present before the submission and raises a validation error instead of a traceback. Forward-Port-Of: odoo/enterprise#127733 Forward-Port-Of: odoo/enterprise#124096
A payroll-related automated test was failing because it used a Sunday, when employees were not scheduled to work. The date has been changed to a Monday so the test reflects a valid working day and avoids false failures.
Original PR description
The test `test_float_holiday_attest` fails with a ValidationError: "The following employees are not supposed to work during that period". The previous patch (cf. PR odoo/enterprise#107490) froze time to "2026-02-01 08:00:00", which was a Sunday. When validating the leave created for `today`, check of the employee's calendar fails because zero working hours are scheduled on weekends. This commit updates `@freeze_time` to "2026-02-02 08:00:00" (Monday) so the leave validation runs against a valid working day. runbot-240132 runbot-241193 Forward-Port-Of: odoo/enterprise#126391
Historical Luxembourg payslips now use the wage index that was valid at the end of the payslip period, rather than today's index. This helps ensure past payroll calculations remain accurate and consistent with the period being processed.
Original PR description
Historical payslips incorrectly used today's wage index instead of the index active during the payslip period. Now, salary rules evaluate the indexed wage using `payslip.date_to` via the new `_get_l10n_lu_indexed_wage(date)` contract method. Task: 6395557 Forward-Port-Of: odoo/enterprise#125861
Large accounting reports now render fewer hidden rows, reducing page weight and improving responsiveness when users fold sections or search. This helps reports with thousands of lines feel faster and easier to navigate until the newer virtual grid solution is available.
Original PR description
When a report has 1 000+ lines, the DOM gets quite heavy which make DOM operation very slow. To help reduce this, we now will minimize the number of components rendered by removing components that previous were just hidden using "d-none" on the line. This will require more creation and suppression of components but it should make the DOM size smaller so it should help on larger reports where a lot of lines are hidden (by folding back a line, or by using the search bar). opw-6427411 opw-6442756 PR Note: this is only required until saas-19.5/20.0 since the virtual grids are added then which will resolve this issue since the virtual grids only render what's in the view of the user with long paddings on top and bottom so only ~70-80 lines are actually rendered. Forward-Port-Of: odoo/enterprise#127516
Payroll configuration now shows Mexico-specific CFDI settings only when the active company is based in Mexico. This avoids confusing or irrelevant options for companies operating in other countries.
Original PR description
Steps to reproduce: 1. Switch to a non-Mexican company. 2. Go to Payroll > Configuration > Settings. 3. The CFDI settings block is visible. Reason: The CFDI block was missing a country check. Solution: Restrict the CFDI block visibility to Mexican companies. Task-6448440 Forward-Port-Of: odoo/enterprise#127022
5 changes
Security fixes and vulnerability patches
This fix prevents users from linking a signature request to records they are not allowed to view. It closes a security gap where hidden record values could become visible through the signing process, keeping Sign requests aligned with normal access permissions.
Original PR description
Version: saas-18.3 Reported issue: 1. Marc Demo creates a sign request from a template whose fields are automatically populated from the linked record. 2. It is sent to himself. He does not have…
Version: saas-18.3 Reported issue: 1. Marc Demo creates a sign request from a template whose fields are automatically populated from the linked record. 2. It is sent to himself. He does not have access to all records of a referenced model (e.g. Sales Orders). 3. The "Linked To" (reference_doc) field is edited afterwards to point to a record the signer does not have access to. By the time it's signed, the value of that record becomes visible - so a user can, simply by changing the linked record, see the value of a record they were never authorized to access. Even a Sign Manager could link a request to a record they have no access to and later see its value through it. Issue: `reference_doc` could be set or changed to any record of any allowed model with no validation that the acting user actually has access to it. In the interface, you can only create a signature request from a record you can see, but editing `reference_doc` manually (via write(), RPC, etc.) was not held to the same rule, making it an easy way to leak information about records outside your normal access. Cause: The only restriction was cosmetic, enforced client-side by the record picker widget filtering its search results. Nothing on the server validated the value being written to `reference_doc`. Fix: `write()` now checks that the acting user has read access to the target record before allowing `reference_doc` to be set, raising a ValidationError otherwise, bringing manual edits in line with what the interface already enforces when creating a request. Forward-Port-Of: odoo/enterprise#127715
Enhancements to existing features
The Dutch payroll module now includes the 2026 resident income tax rates. This helps businesses calculate employee payroll taxes using the latest published values for the new tax year.
Original PR description
Added 2026 values for the residents' income tax rates rule parameter. task-6462877 Forward-Port-Of: odoo/enterprise#127556
Only the person who created a signature request can now change a signer’s email address. This helps prevent unintended or unauthorized recipient changes, improving control and trust in the signing process.
Original PR description
Forward-Port-Of: odoo/enterprise#127582 Forward-Port-Of: odoo/enterprise#126675
Resolved issues and error corrections
Historical Luxembourg payslips now use the wage index that was active at the end of the payslip period, instead of using the current index. This helps ensure older payroll calculations remain accurate when wage index values change over time.
Original PR description
Historical payslips incorrectly used today's wage index instead of the index active during the payslip period. Now, salary rules evaluate the indexed wage using `payslip.date_to` via the new `_get_l10n_lu_indexed_wage(date)` contract method. Task: 6395557 Forward-Port-Of: odoo/enterprise#125861
Odoo now recognizes valid Brazilian electronic invoice XML files even when the invoice tag has no extra attributes. This prevents some vendor bills from being skipped during import, helping accounting teams process compliant invoices consistently.
Original PR description
### Issue before this commit: Certain valid Brazilian NF-e (electronic invoice) XML files fail to import because the system silently ignores them during the initial EDI recognition phase. ### Steps to reproduce the issue: 1. Download Accounting and l10n_br_edi 2. Go to Vendor > Bills 3. Try to import both xmls in the ticket 4. One of the two will not be imported correctly ### Cause of the issue: https://github.com/odoo/enterprise/blob/3ed1721b702555e96c9774969927f6517e855704/l10n_br_edi/models/account_move.py#L819-L827 This function relies on a strict byte string search for b"<NFe " while it's also correct if the tag is only `<NFe>`. ### Reason to introduce the fix: To make the initial NF-e file recognition more robust and compliant with standard XML namespace rules, ensuring Odoo successfully processes all valid Brazilian invoices regardless of attribute formatting. opw-6402843 Forward-Port-Of: odoo/enterprise#126881
8 changes
Enhancements to existing features
Signer email addresses on signature requests can now only be changed by the person who created the request. This helps prevent unauthorized or unintended changes to recipients, improving trust and control in the signing process.
Original PR description
Forward-Port-Of: odoo/enterprise#126675
The Dutch payroll module now includes the 2026 income tax rates for residents. This helps payroll calculations stay aligned with upcoming Dutch tax requirements.
Original PR description
Added 2026 values for the residents' income tax rates rule parameter. task-6462877 Forward-Port-Of: odoo/enterprise#127556
Resolved issues and error corrections
Odoo now correctly recognizes Brazilian electronic invoice XML files even when the main invoice tag has no extra attributes. This prevents valid vendor bills from being skipped during import, reducing manual handling and import failures for Brazilian accounting teams.
Original PR description
### Issue before this commit: Certain valid Brazilian NF-e (electronic invoice) XML files fail to import because the system silently ignores them during the initial EDI recognition phase. ### Steps to reproduce the issue: 1. Download Accounting and l10n_br_edi 2. Go to Vendor > Bills 3. Try to import both xmls in the ticket 4. One of the two will not be imported correctly ### Cause of the issue: https://github.com/odoo/enterprise/blob/3ed1721b702555e96c9774969927f6517e855704/l10n_br_edi/models/account_move.py#L819-L827 This function relies on a strict byte string search for b"<NFe " while it's also correct if the tag is only `<NFe>`. ### Reason to introduce the fix: To make the initial NF-e file recognition more robust and compliant with standard XML namespace rules, ensuring Odoo successfully processes all valid Brazilian invoices regardless of attribute formatting. opw-6402843 Forward-Port-Of: odoo/enterprise#126881
Fixes report printing through IoT devices so a completed print job is properly closed out. This prevents later connection errors after a successful print, reducing disruption for users who rely on IoT-connected printers.
Original PR description
The report printing logic was missing a call to `removeListener` on print success, resulting in an IoT connection error later, even on print success. opw-6469551 Forward-Port-Of: odoo/enterprise#127835
Luxembourg payroll now calculates indexed wages using the wage index that was active at the payslip period end date, rather than today's index. This helps ensure historical payslips and payroll records remain accurate when wage indexes change over time.
Original PR description
Historical payslips incorrectly used today's wage index instead of the index active during the payslip period. Now, salary rules evaluate the indexed wage using `payslip.date_to` via the new `_get_l10n_lu_indexed_wage(date)` contract method. Task: 6395557 Forward-Port-Of: odoo/enterprise#125861
The product catalog in Field Service now gives more space to the unit of measure column. This makes product information easier to read when adding items from a task, aligning the experience with the main Odoo catalog update.
Original PR description
Steps to produce: --- - Install `Field service` module. - Create a task and open it. - From the task open the catalog from smart button. Update the Product Catalog UI to match the Community PR changes. community PR: https://github.com/odoo/odoo/pull/267118 opw-6253382 ---
The Project Forecast settings no longer show the Time Management section unless the Timesheets app controls its visibility. This prevents users from seeing irrelevant configuration options when Timesheets is not installed.
Original PR description
**Steps to reproduce:** - Install the project_forecast module. - Go to Projects -> Open the settings of any project (create one if none exist) -> Settings. - You will see the Time Management section. **Issue:** The project_forecast module was forcefully setting the invisible attribute of group_time_managment to 0. This caused the group to remain visible at all times, even when the Timesheets app was not installed. **Fix:** Remove the forced attribute setting from the project_view. The visibility is already properly managed by the hr_timesheet module, and project_forecast does not depend on timesheet_grid or hr_timesheet. **Merge Till - SaaS-19.1 only, then from SaaS-19.2 : https://github.com/odoo/enterprise/pull/121454** task-6195716 Forward-Port-Of: odoo/enterprise#121565
The General Ledger CSV export now keeps accounts and transaction lines in the same order, even when multiple companies share account codes. This prevents export failures and helps users reliably download complete ledger reports.
Original PR description
Description of the issue this commit addresses: Account and move lines can be returned in different orders when account codes are shared across companies. The CSV generator can then exhaust its account iterator and raise StopIteration. --- Desired behavior after this commit is merged: This commit orders move lines using the account sequence returned by the report, keeping both CSV iterators aligned. --- runbot-[242131](https://runbot.odoo.com/odoo/error/242131) Forward-Port-Of: odoo/enterprise#126619
11 changes
New functionality added to Odoo
Belgian payroll now supports the withholding tax exemption for qualifying investments in aid zones. This helps employers apply the temporary 25% reduction for eligible newly created jobs and include the required 274.81 reporting in payroll declarations and reports.
Original PR description
Implement support for the Belgian withholding tax exemption regarding investments in aid zones. Employers benefit from a temporary 25% reduction in withholding tax remittance on eligible remunerations for newly created jobs. Changes: - Add `l10n_be_is_aid_zone` flag on employee,version models. - Update 274.XX calculation logic to isolate Nature 81 bases and apply the flat 25% rate. - Add "Aid Zone (274.81)" tab in the UI and include its totals in the main Exempted Amounts summary. - Update (XML payload and XLSX report) to include the new 81 code block. Task: 6352132
Enhancements to existing features
The search view editor now hides fields that belong to the search panel from its suggestion list. This reduces confusion for users by only showing relevant fields when configuring search views.
Original PR description
The search view editor displays the fields from the search panel, which can be confusing for the user. This commit filter's out those fields from the autocompletion container. tasl-6366232
Belgian payroll salary rule categories for meal vouchers, representation fees, and private car reimbursements have been renamed to make their purpose clearer. This helps payroll users understand that these categories indicate eligibility, reducing confusion in configuration and reporting.
Original PR description
Meal Voucher, Representation Fees and Private Car Reimbursement categories were renamed from boolean fields and kept awkward, unclear names. Rename them to Meal Voucher Eligible, Representation Fees Eligible and Private Car Reimbursement Eligible. Task 6459956
Studio users can now choose which field is totaled in kanban views directly from the sidebar. This makes it easier to customize dashboards and boards without needing technical changes.
Original PR description
The `sum_field` cannot be set in kanban views through Studio. This commit exposes it as a new property in the sidebar. task-6366141
Spreadsheet dashboards across several business areas have been visually standardized so figures display with consistent sizing, spacing, and backgrounds. A new Employee appraisal dashboard has also been added, and translated dashboard text now displays correctly without being compressed.
Belgian payroll now alerts users when an employee's bank account is invalid. This helps payroll teams catch payment issues before processing salary payments, reducing failed transfers and manual follow-up.
Original PR description
This commit adds a warning message in the Belgian payroll module when an employee's bank account is invalid. task-6458596
Calendar events are now matched to projects or tasks using their direct “linked to” relationship before falling back to customer history. This makes suggested timesheets more accurate, especially when calendar meetings are tied to specific project or helpdesk work.
Original PR description
…ojects via the 'linked to' field Before this commit: - Calendar events are matched based on the most timesheet project of the partners. After this commit: - Calendar events are matched to projects/tasks via the "linked to field" before looking to partners projects. task-6238332
The timesheet Timeline view now displays assistant suggestions in true chronological order instead of sorting them by title. Users can also see each suggestion's start time, making it easier to review and enter work accurately.
Original PR description
Forward-Port-Of: odoo/enterprise#126238 Forward-Port-Of: odoo/enterprise#122862
Resolved issues and error corrections
The Swiss payroll time off form layout has been corrected so HR users can view and complete the form more easily. This reduces confusion when managing employee absences in the Swiss payroll module.
Original PR description
This commit fixes the layout of the time off form view for the Swiss payroll module. task-6275864
This fixes a small compatibility issue in the UK tax reporting screen after a recent reporting framework update. Businesses using UK reports should see the HMRC submission button read report settings correctly, reducing the risk of errors when preparing submissions.
Original PR description
https://github.com/odoo/enterprise/commit/5da8982a0edf9655ef622f1937ebe2cb72abff07 ([IMP] account_reports: Report Virtual Grids and Reactivalypse) made `AccountReportController.options` a signal but forget a caller that (probably) landed in master after the author started its PR (but before he closed it) https://github.com/odoo/enterprise/commit/f648605aac92fa6414bb7ab5f9a4347c3bf7aa05
The AI tools now avoid loading full file contents when reading records, preventing oversized requests and improving reliability. For website-related AI use, file fields can still be referenced through a URL when needed instead of raw data.
Original PR description
Instead of using the binary field raw content and overflowing the context, we are searching with `bin_size=True`. This way, result will contain only binary field's size, instead of the raw content. However, in ai_website it might be useful to have an address of the field, instead of its size, as ai might need to use it.
2 changes
Security fixes and vulnerability patches
Sign requests can no longer be linked to records that the person making the change is not allowed to read. This prevents sensitive record information from becoming visible through signed documents and aligns manual edits with normal interface permissions.
Original PR description
Version: saas-18.3 Reported issue: 1. Marc Demo creates a sign request from a template whose fields are automatically populated from the linked record. 2. It is sent to himself. He does not have…
Version: saas-18.3 Reported issue: 1. Marc Demo creates a sign request from a template whose fields are automatically populated from the linked record. 2. It is sent to himself. He does not have access to all records of a referenced model (e.g. Sales Orders). 3. The "Linked To" (reference_doc) field is edited afterwards to point to a record the signer does not have access to. By the time it's signed, the value of that record becomes visible - so a user can, simply by changing the linked record, see the value of a record they were never authorized to access. Even a Sign Manager could link a request to a record they have no access to and later see its value through it. Issue: `reference_doc` could be set or changed to any record of any allowed model with no validation that the acting user actually has access to it. In the interface, you can only create a signature request from a record you can see, but editing `reference_doc` manually (via write(), RPC, etc.) was not held to the same rule, making it an easy way to leak information about records outside your normal access. Cause: The only restriction was cosmetic, enforced client-side by the record picker widget filtering its search results. Nothing on the server validated the value being written to `reference_doc`. Fix: `write()` now checks that the acting user has read access to the target record before allowing `reference_doc` to be set, raising a ValidationError otherwise, bringing manual edits in line with what the interface already enforces when creating a request. Forward-Port-Of: odoo/enterprise#127715
Resolved issues and error corrections
A leftover "Request Appraisals" action that no longer worked has been removed from the Employees area. Users should use the existing "Launch Campaign" button to request appraisals for multiple employees, avoiding an error and keeping the workflow clear.
Original PR description
#### Description of the issue/feature this PR addresses: The "Request Appraisals" server action on hr.employee calls model._create_multi_appraisals(), a method that no longer exists. Running it…
#### Description of the issue/feature this PR addresses: The "Request Appraisals" server action on hr.employee calls model._create_multi_appraisals(), a method that no longer exists. Running it raises AttributeError: 'hr.employee' object has no attribute '_create_multi_appraisals'. #### Current behavior before PR: Commit 8845eb2ac29 replaced the multi-appraisal flow with hr.appraisal.campaign.wizard: it deleted _create_multi_appraisals and repointed the employee list header button to action_open_appraisal_campaign_wizard, but left the action_create_multi_appraisals record in hr_appraisal/views/hr_employee_views.xml. Its code is now the only reference to the deleted method, so the action crashes whenever it is run. #### Desired behavior after PR is merged: The dangling action is gone. Requesting appraisals for several employees at once is done with the "Launch Campaign" button already present in the Employees list view; action_open_appraisal_campaign_wizard reads active_ids when active_model is hr.employee and pre-fills the selected employees. Nothing references the removed xml id, and the record is not noupdate, so _process_end removes it from existing databases on update; no migration script is required. Verified on a 19.0 database: with the orphan record loaded, updating hr_appraisal with this change deletes it. opw-6408609
4 changes
Enhancements to existing features
The Dutch payroll module now includes the 2026 resident income tax rate values. This helps payroll calculations stay aligned with upcoming tax requirements for employees in the Netherlands.
Original PR description
Added 2026 values for the residents' income tax rates rule parameter. task-6462877 Forward-Port-Of: odoo/enterprise#127556
Resolved issues and error corrections
This fix ensures successful report prints properly clean up their connection callback. It prevents later false IoT connection errors after a print has already completed successfully.
Original PR description
The report printing logic was missing a call to `removeListener` on print success, resulting in an IoT connection error later, even on print success. opw-6469551
This fixes an issue where a person listed more than once on a signature request could be prompted to sign again before earlier signers had completed their step. Signing requests now respect the configured order, reducing mistakes and ensuring documents follow the intended approval flow.
Original PR description
### Steps to Reproduce: 1. Create a sign request and have 3 total signers (User, Customer, Employee) 2. Enable Signing Order and make the order as follows: (1) User, (2) Customer, (3) Employee But…
### Steps to Reproduce: 1. Create a sign request and have 3 total signers (User, Customer, Employee) 2. Enable Signing Order and make the order as follows: (1) User, (2) Customer, (3) Employee But make the User and Employee the same contact 3. Send and sign the request > Notice that (1) is able to sign for (3) immediately after, (2) has not signed yet. ### Description of the issue/feature this PR addresses: **Issue:** The signing order is ignored when the same user has to sign multiple times on a document, even if it is configured for a different person to sign in between. This happens because all signature request items are initialized in the 'sent' state upon creation, rather than strictly advancing based on the order. As a result, the system prematurely allows users to sign out of order and prompts them with their next turn too early. **Solution:** To resolve this, the controller was updated to include an `is_mail_sent = True` domain filter. This ensures that the UI's post-sign popup only displays documents where it is explicitly the user's active turn, rather than prompting a premature sign. ### Current behavior before PR: Users are able to sign prematurely, and the system will disregard the configured signing order. ### Desired behavior after PR: Users will only be prompted and able to sign a document when it is explicitly their turn, per the `mail_sent_order`. This way, documents are signed in order. opw-6417327
Peruvian accounting reports now use the exchange rate already saved on each accounting entry instead of recalculating it later. This reduces rounding differences and helps produce more reliable reported amounts.
Original PR description
Previously, the `_get_ple_report_data` method computed the currency rate when called. Since the calculation was based on the entry totals, it was prone to rounding errors. This PR makes it use the rate stored in the entry itself. This should lead to more accurate results. opw-6411322
2 changes
Resolved issues and error corrections
When bank synchronization finds no new transactions, the reconciliation screen now shows an empty view instead of displaying transactions from all bank journals. This prevents confusion for companies using multiple bank journals and keeps the experience consistent with newer Odoo versions.
Original PR description
Currently, when we fetch zero transaction for an online account through bank synchronization, we open the bank reconciliation view with an empty domain, thus showing every transactions from every journals. This is confusing for the user if they have several bank journals. This commit now shows an empty bank reconciliation widget if no transactions are fetched. Additionally, this aligns with how it works in Odoo 19. [opw-6384718](https://www.odoo.com/mail/message/1138570272)
Invoice scanning now compares bank account numbers in the same cleaned format used by OCR. This helps match supplier IBANs more reliably when saved account numbers contain spaces, dots, or dashes.
Original PR description
When looking for a matching IBAN, we were searching on the `acc_number` field, which can contain spaces or special characters (dots, dashes, etc). But the OCR always returns the IBAN in a sanitized format, without any space or special characters, so it should be compared against the sanitized IBAN of the partners. task-none (issue found by chance)