Friday, August 28, 2026
15 changes · master
Resolved issues and error corrections
Timesheet suggestions created from calendar events now better match the correct project or task and display adjusted event durations correctly after overlaps are resolved. This helps users log time with fewer manual corrections and reduces confusion from inaccurate suggested entries.
Original PR description
task: 6435164 Forward-Port-Of: odoo/enterprise#126680
Website links that open in a new tab are now handled in a way that better supports screen reader users. This helps visitors understand when navigation will leave the current page context, reducing confusion and improving accessibility.
Original PR description
Screen readers generally do not automatically announce that a link opens in a new tab when a user navigates to it, creating a potential barrier for non-visual users who may become disoriented if the current page is replaced without warning. Commit 2135b3c1a89c3ba0887191f36b5d73d08682f4b6 already fixed it, but this new approach follows more closely the Interaction framework.
Certification content in eLearning courses now displays correctly outside fullscreen mode. This ensures learners can access certification lessons consistently in the standard course view.
Original PR description
**Steps to reproduce:**
- Install website_slides_survey module
- Create a course in eLearning
- Add content with type Certification
- Go to the website and open the content
- It renders properly in fullscreen
- It displays nothing in the normal view
**Issue:**
`<xpath expr="//div[hasclass('o_wslides_lesson_content_type')]` targets the wrong `<div>` since [1] (it adds the certification content inside the `t-if="slide.slide_category == 'infographic'"`)
**Fix:**
Match the `t-else` condition as well for the xpath.
Fix in master as view update is needed.
[1] https://github.com/odoo/odoo/commit/e3389e392e3ccf0061e3838923ad9a9b4ea41cdd
opw-6070973This fix stops users from marking the main website menu as a mega menu when it already contains child menus. It prevents migration failures and keeps website navigation settings consistent for sites using apps such as recruitment.
Original PR description
Issue: ------- After the fix: https://github.com/odoo/odoo/commit/f1557211d9e7f83761bb36e4800e4c2f62b234c5 we can't create a child menu for a mega menu or a menu can't be a mega menu when there's an…
Issue:
-------
After the fix:
https://github.com/odoo/odoo/commit/f1557211d9e7f83761bb36e4800e4c2f62b234c5 we can't create a child menu for a mega menu or a menu can't be a mega menu when there's an existing child menu except the case of top level menu i.e; (url: /default-main-menu) and that menu will have no parent_id obviously...
Now, as per the above pr conditions the top level can be set as mega menu since it has no parent id. And in version 17.3 in the pr https://github.com/odoo/odoo/commit/47af533e9f5f721b63570d3b301951f3855384a1 a 'Jobs' menu is being created and its parent_id refers to that top level menu which we have set as mega menu. And when the records gets validated during migration the database will get blocked.
Solution:
-----------
Restrict the user by throwing the same user error, when checking/selecting the top level menu as mega menu since it has existing child menus.
Step to reproduce:
-----------------------
1. Create a database in version 17.0 with 'website_hr_recruitment' installed.
2. Go to website menus, set a top level menu(/default-main-menu) as mega menu.
3. Migrate the database to version 18.0 or more.
Traceback:
```
File "/home/odoo/src/odoo/18.0/odoo/models.py", line 5297, in _create
records._validate_fields(name for data in data_list for name in data['stored'])
File "/home/odoo/src/odoo/18.0/odoo/models.py", line 1636, in _validate_fields
check(self)
File "/home/odoo/src/odoo/18.0/addons/website/models/website_menu.py", line 95, in _validate_parent_menu
raise UserError(_("A mega menu cannot have a parent or child menu."))
odoo.exceptions.UserError: A mega menu cannot have a parent or child menu.
File "/home/odoo/src/odoo/18.0/odoo/tools/convert.py", line 603, in _tag_root
raise ParseError('while parsing %s:%s, somewhere inside\n%s' % (
odoo.tools.convert.ParseError: while parsing /home/odoo/src/odoo/18.0/addons/website_hr_recruitment/data/config_data.xml:13, somewhere inside
<record id="website_menu_jobs" model="website.menu">
<field name="name">Jobs</field>
<field name="url">/jobs</field>
<field name="parent_id" ref="website.main_menu"/>
<field name="sequence">59</field>
</record>
```
Ref Images:
Before Fix:
<img width="1598" height="599" alt="image" src="https://github.com/user-attachments/assets/ef719945-a11b-4134-97f8-4b583c4ea6bc" />
After Fix:
<img width="1582" height="633" alt="image" src="https://github.com/user-attachments/assets/da326e45-0de8-4d42-ad47-845bfaedc84e" />
OPW - 6094298
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#280458
Forward-Port-Of: odoo/odoo#263025This fixes an error that appeared when users tried to generate a new serial or lot number for components during a manufacturing barcode operation. Manufacturing teams can now continue barcode workflows without being blocked by this issue.
Original PR description
When generating a serial/lot number in a manufacturing opperation in barcode you get an error. Steps to reproduce: 1. Create a new manufacturing picking for a product with component 2. For the components try to generate a new serial number by clicking the + button 3. An error message shows up
This fix restores the ability to set holiday table values through payroll rule parameters instead of always calculating them automatically. It matters because companies can keep different values for different employees when Mexican payroll requires that flexibility.
Original PR description
In this PR: odoo/enterprise#120199 We replaced the rule parameter for the holiday table by a method to get it automatically. The problem is that the user might want to have different values for different employees. Task: 6512040
This fixes an issue where planning slots with multiple assigned resources could show incorrect allocated hours after resources were added or removed. Working time is now calculated per resource, helping schedules and capacity figures remain accurate for field service planning.
Original PR description
## Steps to reproduce: - Install planning_field_service - Create a planning slot with one resource - Add another resource for the slot we created - Notice the allocated_hours now equals 16h - Remove one of the resources - Notice now the allocated hours are 5h instead of 8h ## Cause: When adding a second resource in a slot and while computing the break_time we use the working hours of all of the resources combined instead of dividing by the number of resources and this messes up the break_time calculation which affects the allocated_percentage and at the end when trying to compute the allocated hours it will be wrongly calculated ## Fix: We divide the working hours by the number of resources to be able to compute the break_time correctly. opw-6307906 Forward-Port-Of: odoo/enterprise#129439 Forward-Port-Of: odoo/enterprise#125641
Submitting a tax report opened from a return now reliably updates the same return shown on screen. This prevents Dutch VAT corrections from being accidentally submitted or marked against the original VAT return for the same period.
Original PR description
Opening a tax report from a return and submitting it could act on a different return than the one on screen. _get_return_from_report_options searches by company, period and report with limit=1, but…
Opening a tax report from a return and submitting it could act on a different return than the one on screen. _get_return_from_report_options searches by company, period and report with limit=1, but that combination is not unique: l10n_nl declares two return types on l10n_nl.tax_report, nl_tax_return_type and nl_tax_correction_return_type, so a VAT return and its correction both match. Which one is returned is then decided by _order (is_completed, date_deadline, name, id). For a Dutch VAT correction it resolves to the original VAT return of the same quarter, so send_xbrl submits and flags that record instead of the correction. The options already carry the return type they were built for, in the return_periodicity filter, so restrict the search to it when it is set. l10n_nl_reports kept a return_id option for the same reason when computing the already declared amount of a suppletie; it can use _get_return_from_report_options now. opw-6421300 Forward-Port-Of: odoo/enterprise#129278 Forward-Port-Of: odoo/enterprise#127073
The signing process now creates completed documents at the right moment and avoids showing duplicate attachments on related records. Users get clearer completion messages and can find signed files reliably in the attachment tray.
Original PR description
This commit refactors the document completion flow to enforce the SRP and resolve duplicate attachments on reference records. Changes include: - Moved PDF generation (`_generate_completed_documents`) from the send method directly into `_sign` to guarantee documents are built exactly when the state changes to 'signed'. - Extracted reference record updates into a dedicated `_update_reference_document` method for cleaner code structure. - Resolved duplicate attachment displays on the source record by explicitly creating the attachment once and removing the redundant `attachment_ids` from the chatter message. - Updated the completion chatter message to notify users that the files are in the attachment tray, and set the message author to the original request creator. - Overrode `_generate_done_message` to cleanly bypass generic activity messages. Task: 6127862
Invoice and journal entry numbering now checks for missing numbers within each suffix-based sequence separately. This prevents valid entries from being incorrectly highlighted as gaps, improving confidence in accounting sequence checks.
Original PR description
### Issue: When moves share the same `sequence_number` in a journal but have different suffixes (e.g. `INV/2026/00010` and `INV/2026/00010A`), the `made_sequence_gap` flag was incorrectly set ###…
### Issue: When moves share the same `sequence_number` in a journal but have different suffixes (e.g. `INV/2026/00010` and `INV/2026/00010A`), the `made_sequence_gap` flag was incorrectly set ### Cause: `_update_sequence_made_gap`, introduced in commit https://github.com/odoo/odoo/commit/17893089e8b21c0ecab5e61ed8e2c33f3731b3ac selects the previous and next moves ordered by `sequence_number` without filtering by suffix This causes two issues: - Moves from different suffix sequences are used as neighbors, leading to incorrect gap detection - Duplicate `sequence_number` values across suffixes are not accounted for, so only one move is considered per number ### Steps to reproduce: - Install `account` - Post 12 invoices to get a sequence up to `INV/2026/00012` - Reset `INV/2026/00012` to draft, rename it to `INV/2026/00010A` - Reset `INV/2026/00010A` to draft, rename it to `INV/2026/00009A` and confirm Before the fix: `INV/2026/00011` is red Expected: `INV/2026/00011` should not be red because `INV/2026/00010` exists - Delete `INV/2026/00009` Before the fix: `INV/2026/00010` is red Expected: `INV/2026/00010` should be red (gap in no-suffix sequence) - Reset `INV/2026/00009A` to draft and confirm it again Before the fix: `INV/2026/00010` is not red Expected: `INV/2026/00010` should still be red (different suffix) ### Notes: Suffix changes are treated as distinct sequences following the same gap rules as any other sequence This was agreed with R&D — the gap flag is meant to signal inconsistencies within a sequence, not across suffixes opw-6454823 Forward-Port-Of: odoo/odoo#282503
Odoo now saves the updated Microsoft refresh token whenever calendar access is renewed. This prevents users from being unexpectedly asked to reconnect their Microsoft Calendar after the old token expires, reducing disruption for calendar synchronization.
Original PR description
Microsoft issues a new refresh token on every access token refresh (rolling 90-day sliding window). The previous code discarded it, causing users to be forced to re-authenticate every 90 days once the original token expired. Closes #253543 Forward-Port-Of: odoo/odoo#280535 Forward-Port-Of: odoo/odoo#268284
This fix ensures costs are correctly linked to the right sales order when projects share the same analytic account or when a cost line uses multiple analytic accounts. Businesses get more reliable reinvoicing, reducing missed billable costs and manual corrections.
Original PR description
### Before this fix --- The `_get_so_mapping_from_project()` method returns a mapping where the key is the move line ID and the value is a `sale.order` record (or `None`). Because of the issues…
### Before this fix
---
The `_get_so_mapping_from_project()` method returns a mapping where the key is
the move line ID and the value is a `sale.order` record (or `None`).
Because of the issues described below, a valid `sale.order` could be available
for reinvoicing, but the corresponding move line might still not be mapped to
that sale order. As a result, the move line is not added to the reinvoiceable
sale order.
However, the implementation has two issues:
#### 1. Projects are overwritten when they share the same analytic account
`project_per_accounts` is built as a dictionary mapping an analytic account ID
to a single project. If multiple projects reference the same analytic account,
each new assignment replaces the previous one. As a result, only the last
project associated with a given analytic account is retained.
**Example:**
* Analytic Account **AA1** is linked to **Project A** and **Project B**.
* The dictionary becomes `{AA1: Project B}`.
* **Project A** is lost, even though it also references **AA1**.
**Steps to reproduce:**
1. Create an analytic account **AA1**.
2. Create **Project A** and **Project B**, both linked to **AA1**.
3. Create **Sale Order SO1** linked only to **Project A**.
4. Create a vendor bill (or expense) that generates an AML using **AA1** for a
product configured with **Reinvoice Costs = At Sales Price**.
5. Validate the document.
**Expected behavior:**
The product should be added to **SO1** for reinvoicing.
**Actual behavior:**
The move line is not mapped to **SO1**, so no sale order line is created.
#### 2. Previously found projects are overwritten during iteration
The `project` variable is reassigned on every iteration of the loop. After the
loop completes, it only contains the project (or lack of one) corresponding to
the last processed analytic account. This can cause valid projects found earlier
in the loop to be discarded.
**Example:**
* Move line has analytic accounts **AA1** and **AA2**.
* **AA1** maps to **Project A**.
* **AA2** has no linked project.
* After the loop, `project` is `None`, even though **Project A** was found.
**Steps to reproduce:**
1. Create analytic accounts **AA1** and **AA2**.
2. Create **Project A** linked to **AA1** only.
3. Create **Sale Order SO1** linked to **Project A**.
4. Create a vendor bill (or expense) whose AML is distributed between **AA1**
and **AA2**, where **AA2** is processed after **AA1**.
5. Validate the document.
**Expected behavior:**
The move line should still be mapped to **SO1** because **AA1** references
**Project A**.
**Actual behavior:**
The last processed analytic account (**AA2**) overwrites the previously found
project, causing the move line not to be linked to **SO1**.
### After this fix
---
* `project_per_accounts` stores **all** projects associated with each analytic
account instead of keeping only the last one.
* The project lookup preserves all valid project candidates instead of
overwriting previously found results during iteration.
* As a result, the method can resolve the related `sale.order` in more cases,
improving the overall accuracy of the mapping.
> **Note:** This change prevents valid project associations from being lost
> when multiple projects share an analytic account or when multiple analytic
> accounts are processed for the same move line.
**OPW:** 6294615
Forward-Port-Of: odoo/odoo#277110Fixed an issue where invoices created from Point of Sale orders in Chile were not automatically sent to the SII tax authority. This ensures business customers receive compliant invoice processing after checkout without manual follow-up.
Original PR description
Issue: Invoices from PoS orders are not automatically send to SII. Steps to reproduce: - Open PoS - create an order - add a company as customer - pay - close register - go to invoice Current behavior: Invoice is created but not sent Expected behavior: Invoice is created and send to SII. Cause: Before 19.2 invoices were sent using a cron. Starting from 19.2, invoices are sent using the Send button of the invoice form. In order to get a perf improvement, PDF generation was deactivated for l10n_cl PoS invoices at creation. However, the same method used to generate the PDF is used to send the invoice to SII. Therefore, invoices from PoS were not sent to SII. opw-6423528 Forward-Port-Of: odoo/enterprise#126623
Unreconciling one bank statement line from an invoice or bill now only removes that specific match instead of clearing all related reconciliations. This prevents accidental loss of payment matching when multiple bank statements are tied to the same document.
Original PR description
**STEP TO REPRODUCE** 1. Create a bill or an invoice. 2. Create multiples bank statement. 3. Reconciles those bank statements to the invoice/bill. 4. Unreconciles one of those bank statement on the invoice/bill. 5. Notice the invoice/bill is completely unreconciled. Expected behavior: only the unreconciled line should be unreconciled. **CAUSE** When unreconciling a partial linked to a bank statement, we call `delete_reconciled_line()` on both `partial.credit_move_id` and `partial.debit_move_id`. One on those is the the payment_term line of the invoice/bill the bank statement line is reconciled with. This payment_term line is also linked to all partial reconcilliation line on the invoice/bill, so calling `delete_renconciled_line()` delete all the reconciled line of the invoice/bill. **FIX** We should call `delete_renconciled_line()` only on the bank statement move line, not on the payment term line. opw-6465096 Forward-Port-Of: odoo/enterprise#128126
Swedish ISO20022 batch payments now generate files that correctly match the selected pain.001.001.09 format. This prevents banks from rejecting payment files that were labeled as the newer format but still contained older-format content.
Original PR description
**Steps to reproduce:** - Install Accounting and l10n_se - Switch to a Swedish company (e.g. SE Company) - In Accounting settings, set "Identification" with anything - In Bank journal: * Set an…
**Steps to reproduce:** - Install Accounting and l10n_se - Switch to a Swedish company (e.g. SE Company) - In Accounting settings, set "Identification" with anything - In Bank journal: * Set an account number * Make sure "Swedish ISO20022" is available in "Outgoing Payments" * Set "pain.001.001.09" as "XML Format" in "Outgoing Payments" - Create a vendor payment: * Vendor: [a vendor with a trusted bank account] * Payment Method: Swedish ISO20022 * Amount: [any] - Confirm the payment - From the payments list, select the payment and create a batch - Validate the batch payment **Issue:** When the batch is validated, a `pain.001.001.09` file should be generated. However, its content is that of a `pain.001.001.03` file, even if the version reported in the file is `pain.001.001.09`. For example, `<ReqdExctnDt>` should contains a subnode `<Dt>` in `001.001.09`, which is not the case. It leads to the file being rejected as non-compliant to `pain.001.001.09`. opw-6472050 Forward-Port-Of: odoo/enterprise#129506 Forward-Port-Of: odoo/enterprise#128598