Friday, August 28, 2026
40 changes · master
Enhancements to existing features
Odoo now handles very large groups of records more efficiently by deciding when to reduce automatic preloading based on the original list size. This should lower unnecessary database work and improve performance in areas that process many records, such as accounting, mail, point of sale, exports, website, and attachments.
Original PR description
The previous approach was splicing the recordset in the __iter__ into batches of record with prefetch_ids equal in size to PREFETCH_MAX. This resulted in the iterator not being able to differentiate…
The previous approach was splicing the recordset in the __iter__ into batches of record with prefetch_ids equal in size to PREFETCH_MAX. This resulted in the iterator not being able to differentiate whether it comes from a large recordset or not. Which made the caching method to be used for this recordset not known as we dont have enough information on the recordset when it reaches the fetch. This made way for a lot of ad hoc fixes to detect earlier when the recordset is big enough to disable the prefetching. Currently, the slicing is removed so checking on the size of the original recordset can be done directly with getting the size of the prefetch_ids. This means that we can disable the prefetching for large recordsets on the fly without needing to change the context on a specific recordset. This also allows us to have a smaller callstack and lower number of queries per recordset. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The employee Overtime button now opens a pivot table instead of a collapsed list, making overtime information visible immediately. This helps payroll and HR users review overtime by type and month without manually expanding grouped records.
Original PR description
The employee's "Overtime" smart button opened an hr.leave list view grouped (collapsed) by year then type, so nothing was visible until every group was manually expanded. This commit replaces it with a Pivot view (work entry type rows, month columns, duration in hours as measure) and swaps the old group-by search defaults for the search view's existing "this year" filter default, so the button actually shows data on open. Task 6498778
This update improves how large sets of records are handled during German DATEV CSV exports. It helps reduce unnecessary system load, making large exports more efficient and reliable for businesses processing significant accounting data.
Spreadsheet pivots now prevent users from inserting configurations that rely on unsupported relation fields with non-numeric IDs. This avoids broken pivot tables and guides users with clearer disabled controls and tooltips.
Original PR description
Prevent inserting a pivot into a spreadsheet when it contains groupbys on relations whose IDs are not numeric (e.g. account.root uses string IDs), as the pivot table engine does not support them. The insert button is now disabled with an appropriate tooltip, and the layout configurator filters out blacklisted relations from the dimension field selector. Task: 6023622
This update improves how company configuration is shared across branch structures in Odoo. It helps businesses keep related branches aligned with common settings, reducing duplicate setup and making administration more consistent.
Original PR description
task-6341281 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Belgian payroll settings can now be shared more consistently across company branches. This reduces duplicate setup work and helps keep payroll configuration aligned for businesses operating with multiple branches.
Original PR description
task-6341281
Employees who join after the BPJS Kesehatan billing cut-off will no longer have that contribution taken from their first payslip. The missed amount is tracked as arrears so it can be included in a later payslip, improving payroll fairness and accuracy.
Original PR description
Employees who join after the BPJS Kesehatan billing cut-off should not be charged on their first payslip. Any missed contribution is carried forward as arrears and can be included on the following payslip. task-6002251
The payroll dashboard now shows warning cards much faster by reusing the last known browser-saved state while updated checks run in the background. It also fixes a crash that could happen after dismissing all warnings when upcoming pay run dates were displayed.
Original PR description
Payroll warnings on the dashboard were loaded one by one, blocking the page until every warning finished computing and giving a poor first-load experience. Warnings now render instantly from the…
Payroll warnings on the dashboard were loaded one by one, blocking the page until every warning finished computing and giving a poor first-load experience. Warnings now render instantly from the browser's local store of the last known state, while the real computation still runs per warning in the background: - On a fresh browser, warnings load progressively as before, and get stored locally once computed. - On a later visit, stored warnings appear instantly with a spinner while they recompute in the background. - Once recomputed, a card updates in place, fades out if no longer valid, or fades in at the correct date if newly valid. Bug fix:- Steps to reproduce:- 1. Set schedule on payroll dashboard. 2. Dismiss every warning. 3. On dismissing last warning throws a traceback. Root cause:- `DashboardEmptyScreen` passed the raw closing_date value straight from the RPC response into formatDateLabel, which calls date.diff(...) assuming a Luxon DateTime. The RPC layer serializes it as a plain ISO string, so formatDateLabel crashed with "date.diff is not a function" any time the empty-dashboard screen rendered with upcoming pay runs. Fix:- added new method `formatClosingDate` to format `closingDate` seperately. task-[6240120](https://www.odoo.com/odoo/project/1251/tasks/6240120)
Assistant Rules screens for timesheets have been redesigned to make them easier to read, search, and manage. The update improves consistency across list, kanban, form, and search views, with supporting cleanup that should make the feature more reliable and maintainable.
Original PR description
This PR overhauls the list, kanban, form and search views of the Assistant Rules for clarity and consistency, along with a few related fixes and cleanups on the `aw.rule` model. Task-6116508
New project document folders now automatically inherit the available actions configured on their parent folder, making setup easier across projects. Folder access is also aligned with project visibility, and internal project followers are synchronized as folder members when visibility changes.
Original PR description
- This commit makes the newly created project's document folder have the parent folder's available embedded actions enabled by default. It is done to easily enable actions for all the project folders. - The visibility of the project impacts the internal access of the related folder. Here is the mapping of the project's visibility with the document's rights: | Visibility | Internal Access | |--------|--------| | Invited Internal Users | None | | Invited Internal and Portal Users | None | | All Internal Users | Editor | | All Internal Users and Invited portal users | Editor | Also, when the project's visibility changes, the members of the related document folder are also synchronized with the project's internal followers users. Task-6025723
Turkish payroll has been updated to apply the 2026 SGK social security contribution rules, including new minimum and ceiling checks for the SSI contribution base. The change also simplifies how employee and employer contributions are calculated and lets companies apply the relevant employer incentive reduction.
Original PR description
Update Turkish payroll localization to reflect 2026 SGK regulatory parameters and restructure SSI contribution rules: - Consolidate employee SSI contribution (Disability 9%, Health 5%, Short-Term 0%, Unemployment 1%) under a single salary rule (SSIEDED). - Consolidate employer SSI contribution (Disability 12%, Health 7.5%, Short-Term 2.25%, Unemployment 2%) under a single salary rule (SSICDED). - Remove obsolete standalone unemployment salary rules (SSIDED and SSIUCDED) and their related rule parameter. - Add SSI base amount minimum and update the SSI base ceiling rule parameters, and clamp the SSI contribution base between them. - Add l10n_tr_incentive_tier field on res.company and res.config.settings (0, 2, or 5 points) to deduct incentive points from the employer SSI contribution rate. **task-6397284**
Belgian payroll now better supports economic unemployment compensation, including specific handling for CP302 and clearer separation for CP200 employees. This helps payroll teams apply the right compensation rules and receive a reminder when required inputs are missing.
Original PR description
This commit adds the rules to support economic unemployment for CP302 and updates the existing setup. Key changes: * Add the 'ECONOMIC_UNEMPLOYMENT_BASE' category to better group economic and temporary unemployment rules. * Split the EUC rule into two separate rules: - 'EUC_CP200': For CP200 employees (uses a property input). - 'EUC': For all other joint committees. * Add a warning for 'EUC_CP200' to remind the user to set the input, which defaults to 0.0. * Rename the 'EUB' and 'EUT' rules to fit the new changes, and include the necessary upgrade script. * Add tests for the new rules and calculations. Task #6365138
Deleting an account now benefits from added database indexes in Accounting and Point of Sale. This reduces delays caused by background dependency checks, improving responsiveness for users managing account records.
Original PR description
Without these indexes, the foreign key check when deleting an account can take a long time. Forward-Port-Of: odoo/odoo#284780
HR users can now see which employees and material resources are linked to a working schedule directly from smart buttons. When a schedule is shared across employees, the system warns users and offers to duplicate it for the current employee, reducing accidental changes that affect multiple people.
Original PR description
Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: . Add a smart button that list the employees linked to the working schedule . Add a smart button that list the material resources linked to the working schedule . Show a “Shared Across Employees” warning when navigating from the Employee model, with an option to duplicate and edit the record for the current employee, automatically linking the newly created record to that employee. task-6106525 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Turkish Nilvera e-invoice users no longer need a separate step to retrieve the official PDF once an invoice is accepted. The status sync now also fetches the PDF for successful invoices, handles additional successful commercial invoice statuses, and allows retrying sync when the status is unknown.
Original PR description
Getting the official Nilvera PDF on an invoice took three steps: wait for the status cron to run, wait for the invoice to be accepted by GİB, then click "Fetch Nilvera e-invoice PDF". The sync button…
Getting the official Nilvera PDF on an invoice took three steps: wait for the status cron to run, wait for the invoice to be accepted by GİB, then click "Fetch Nilvera e-invoice PDF". The sync button next to the Nilvera status only refreshed the status and stopped there, so the user had to come back to the invoice later for the document itself. Fetch the PDF right after the status refresh for the invoices that came back successful, and drop the now redundant button from the form view. Pending invoices are filtered out beforehand so they are not polled a second time by the PDF routine. A commercial invoice does not stay on 'succeed'. Once GİB accepts it and the recipient answers, the status is overwritten with 'commercial_approved' or 'commercial_answered_automatically', and both are terminal successes. Group the three in a constant and use it at every PDF gate. In the PDF routine those invoices previously matched none of the status branches, so they were dropped without being fetched, reported pending or reported failed. 'commercial_rejected' stays out: a rejection is not a success, and its PDF is already fetched by the rejection handler. Also show the sync button when the status is "Unknown": e-archive invoices stay unknown until GİB generates its report at 20:00 GMT+3, which is precisely when the user wants to poll again. The status cron already covers that status, the view was the odd one out. task-6434404 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Spreadsheet users can now create a new global filter directly from the related filters area in the side panel. When a field is selected, the filter editor opens with relevant fields already filled in, reducing manual setup and making spreadsheet filtering faster.
Original PR description
Task: 6079698
Turkish e-Archive invoices can now identify e-commerce sales and include the required payment, website, shipment, and delivery details. This helps businesses comply with GiB requirements and prevents invoice export when mandatory e-commerce information is missing.
Original PR description
Purpose: Turkiye e-Archive regulations require invoices generated from e-commerce sales to include specific tracking and fulfillment information. Previously, the system did not distinguish between…
Purpose:
Turkiye e-Archive regulations require invoices generated from e-commerce sales
to include specific tracking and fulfillment information. Previously, the system
did not distinguish between standard sales and e-commerce sales, which is
required by GiB.
Modifications:
-Introduced stored computed field `l10n_tr_sales_type`('normal', 'website') on
'account.move', allowing users to control whether e-commerce nodes are included.
-Made `l10n_tr_sales_type` and `l10n_tr_gib_invoice_type` required when
`l10n_tr_nilvera_customer_status = 'earchive'`.
-Updated e-Archive XML generation to automatically inject required e-commerce
nodes when `l10n_tr_sales_type` is set to 'website'.
-Added validation checks to block export if required e-commerce details are missing.
Key additions for e-commerce sales include:
-Identifies the order as e-commerce sale and includes specific website domain.
-Adds payment details such as agent name, method used (e.g., Credit Card, Wire
Transfer, Payment Provider), and payment date.
-Includes logistics data like carrier/driver name, Tax ID (VKN/TCKN), and
shipment/delivery date.
Related Upgrade PR: https://github.com/odoo/upgrade/pull/10981
task-6236315This update adds checks to ensure payroll rule data files are kept up to date for several country localizations. It helps reduce payroll configuration inconsistencies and supports more reliable payslip processing in Bangladesh, Kuwait, Indonesia, Iraq, Oman, Romania, and Pakistan.
Original PR description
. Add check that the rules data files are updated on localizations . Add _get_data_files_to_update() method for bd, kw, id, iq, om, ro, pk localizations task-6456276
This update improves the website shop pickup experience by refining how warehouse pickup locations and exceptional closing information are shown. Customers should get clearer information when choosing where to collect an order, reducing confusion and support questions.
Original PR description
Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Holiday pay payslips now hide day-tracking details that are not useful in the salary computation view, making the screen easier for payroll users to read. Related time-off values are also clearly labeled in days, reducing confusion when reviewing Belgian payroll calculations.
Original PR description
This commit improves the user experience with the following changes: - Hide "Right to time off", "Time off already taken", and "Additional Vacation Taken" inputs from the "Salary Computation" tab on Holiday Pay N and N-1 payslips. - Set the display visibility rule for these fields to "Never". - Add a "Days" unit to the "Time off", "Right to time off", and "Additional Vacation Taken" rules. Task: 6222665
Notifications have been refreshed to be smaller, clearer, and easier to follow. A new progress bar shows when a notification will disappear, improving the user experience across several Odoo apps.
Original PR description
A big part of the notification behaviour that was in the notification service has been move to the component "Notification". With this comes also a visual cleaning of the notification. Smaller, more compact and with a progress bar that show when the notification will disappear. TASK-ID: 4334047
The Manufacturing Order Overview now includes subcontracted production details, making it easier for users to understand outsourced manufacturing steps alongside regular production information. This improves visibility for teams managing subcontracting through purchase and manufacturing workflows.
Original PR description
Handle subcontracted productions in MO Overview. task: 5225952 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Manufacturing order overviews now include a planning simulation that considers work center availability, similar to the existing bill of materials overview. This helps business users assess scheduling feasibility earlier without changing component availability assumptions.
Original PR description
Simulate planning in MO Overview task: 4455170 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
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
Code cleanup and technical improvements
This update restructures how mail and chat data is calculated and refreshed behind the scenes, reducing unnecessary recalculations and making state changes more predictable. It also fixes several issues found during the cleanup, including attachment typing, pinned chat behavior, and missing CRM typing declarations.
Original PR description
Commit 1. Before this commit, `Record.onChange` binds its two functions to what `this` is at the call site. A record is only reachable as its proxy once the constructor is over, so a registration has…
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
Commit 1. Before this commit, `Record.onChange` binds its two functions to what `this` is at the call site. A record is only reachable as its proxy once the constructor is over, so a registration has to wait for `static new`, where `super.new` has returned it, and both models that register one override `static new` for nothing else. This commit resolves the proxy when the functions run rather than when they are registered, so `setup` can register an onChange, and moves both models to it. Commit 2. Before this commit, a value computed from a record can only be a field with a `compute`, and the model guesses whether that value needs storing: `fieldsComputable` picks the lazy plain-valued fields with eight conditions and a regular expression run on the compute's source. This commit adds `fields.computed()`, so the declaration answers instead of the model: the value is computed on the first read and kept in an owl computed of its own, which the model neither stores nor serializes. The 36 fields the detection was picking are declared instead, so `fieldsComputable` lists what the declarations name and the guessing goes. A `compute` left on a field is scheduled and stored. A computed has no `onUpdate`, so the two fields that had one register an `onChange` from `setup`. This also converts four getters that rebuild a collection on every read, so each one runs on a change instead of on every read. This also fixes what the conversion turned up: - `extra_body_attachment_ids` is declared as an `Attr` whose target model lands as its default value, where the compute returns records: the field becomes a `Many`. - three writes to `is_pinned` in `discuss.channel` never reach the member, as its compute owns the value: opening a channel, opening its chat window and undoing an unpin now set `unpin_dt`, what the compute reads and what the server writes to pin. `updateAttr` warns on such a write instead of dropping it in silence. - `crm.lead` has no `models` declaration and no `@crm` path alias, so the `@this` of its compute names the raw class and the computed value stays untyped. The enterprise counterpart declares `helpdesk.ticket` the same way. Commit 3. Before this commit, a value that goes stale on its own is kept by `Record.computedUntilStale`, a per-record store of its own next to the one `fields.computed` uses. The problem is that the same value needs a key repeating its name, a getter to read it through, and a second place to look for a record's computeds. This commit takes the delay as a third argument of `fields.computed`, so the two clock values of the store are declared like any other computed, and `staleComputeds` goes.
This change speeds up manufacturing-related bill of materials checks, especially when confirming large purchase orders with many lines. Businesses using manufacturing, purchasing, sales, point of sale, repairs, or subcontracting should see less slowdown when Odoo needs to evaluate potential kits or components.
Original PR description
Confirming a purchase order of 1000 lines - with only stock & purchase : time is 6.3secs - by adding mrp : time grows to 8.1secs Part of the difference comes from the time it takes to explode the…
Confirming a purchase order of 1000 lines - with only stock & purchase : time is 6.3secs - by adding mrp : time grows to 8.1secs Part of the difference comes from the time it takes to explode the (potential) kits. The refactor of _bom_find consists of: - signature change : company_id -> company_ids to allow searching within multiple companies in one go - return value change : the returned dict's key is now a tuple ( product, company_id or False) Calling _bom_find with no company given : retrieve result with ( product, False) Calling _bom_find with one or more company_id's : retrieve result with ( product, company) -> for _bom_find on record sets having the fields product_id & company_id With this, use case time falls to 6.9secs This will obviously have performance impact on many use cases. Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr