Saturday, September 19, 2026
11 changes · master
Enhancements to existing features
Calendar users can now view the other members of a shared calendar, even when they are not the calendar owner. This makes it clearer who can see shared events and helps users understand their collaboration context.
Original PR description
Users should be able to see other calendar members, even if they don't own the calendar. It is useful to know who you are sharing your events with. Task-6574702 Forward-Port-Of: odoo/odoo#289107
Small-screen views now present action buttons, menus, status controls, and pagers in a clearer, more consistent layout. This makes Odoo easier to use on phones and tablets by grouping related controls together and making buttons more visually consistent.
Original PR description
task-6564150 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#288472
The control panel has been adjusted so buttons and search actions fit better on small screens. Users working on phones or narrow displays will see cleaner menus, easier access to key actions, and less crowded headers across affected apps.
Original PR description
task-6564150 Forward-Port-Of: odoo/enterprise#131684
Resolved issues and error corrections
This fix corrects how Point of Sale session reversals are recorded so they can be properly matched with customer invoices. It also makes related reversal entries visible from the session invoice button, improving accounting traceability.
Original PR description
Two lines were added into the reverse moves of the session. But these lines were added to the same account. So its the same as having no lines To be able to add the reconciliation between the new partner invoice and the reversal, the payment reversal lines is now on the partner receivable account. Also, the invoices action button on the pos.session form is now also showing the reversal move. Forward-Port-Of: odoo/odoo#288910
This fix corrects how reversal entries are handled for Mexican point-of-sale sessions so they can be properly matched with the related customer invoice. It also makes reversal entries visible from the session invoice button, improving accounting traceability.
Original PR description
Two lines were added into the reverse moves of the session. But these lines were added to the same account. So its the same as having no lines To be able to add the reconciliation between the new partner invoice and the reversal, the payment reversal lines is now on the partner receivable account. Also, the invoices action button on the pos.session form is now also showing the reversal move. Forward-Port-Of: odoo/enterprise#132153
Planning now shows each employee or resource only their own allocated hours when a shift is shared, avoiding overstated workload in the Gantt view. Field service planning also calculates break time correctly when resources with different schedules are added or removed, keeping allocated hours accurate.
Original PR description
# [FIX] planning: split gantt progress bar hours per resource Issue: ---------------------------------------- On the planning gantt view, when a shift is assigned to several resources, the progress…
# [FIX] planning: split gantt progress bar hours per resource Issue: ---------------------------------------- On the planning gantt view, when a shift is assigned to several resources, the progress bar of each individual resource shows the sum of all resources' allocated hours instead of that resource's own hours. Steps to reproduce: ---------------------------------------- - Give two employees working calendars with a different number of daily hours (e.g. 8h and 4h) - Create one shift covering both calendars' full working hours and assign both employees to it - Open the gantt view and check the progress bar of each employee for that shift Cause: ---------------------------------------- `_gantt_progress_bar_group_by_field()` computes one duration per shift via `_get_duration_over_period()`, which already sums the working hours of every resource assigned to the shift. That same total is then added to the progress bar of each resource. Solution: ---------------------------------------- Add `_get_working_hours_over_period_per_resource()` and `_get_duration_over_period_per_resource()`, which returns the results into a dict per resource. `_get_working_hours_over_period()` then calls `_get_working_hours_over_period_per_resource()` and sums the values. `_gantt_progress_bar_group_by_field()` now calls this per-resource breakdown when grouping by `resource_ids`. # [FIX] planning_field_service: fix break_time computation Issue: ---------------------------------------- When adding multiple resources to a slot, we can break the Steps to reproduce first issue: ---------------------------------------- - Create a slot for a resource working 8 hours per day - Add another resource working 4 hours per day - Remove the resource working 4 hours - The allocated hours show "9h 36m" instead of 8h Cause: ---------------------------------------- `_get_in_schedule_break_time()` can return negative values, so it breaks the computation of `allocated_percentage` which then impacts the future allocated percentages. Solution: ---------------------------------------- Add a `max(..., 0)` to `_get_in_schedule_break_time()`. Steps to reproduce second issue: ---------------------------------------- - Create a slot for a resource working 8 hours per day - Add another resource working 4 hours per day - The break time is 0, it should be 4h Cause: ---------------------------------------- The calculation of `break_time` with multiple resources was supposed to be fixed in 583ccb226970787b9dbd4cb03ccbfd43849fb8c7 but the value is never used. Using it fixes the case for multiple resources having the same work schedule but not all case: In our case it will output 12 allocated hours and 2 hours of breaktime instead of 4. This is because the breaktime hours are only from one resources but they still get divided by the number of resources. Solution: ---------------------------------------- We should instead multiply the duration by the number of resources to get the correct number of break hours. This ensures that `allocated_hours + break_time` equals the total duration of the shift. Same in `_get_in_schedule_break_time()`. opw-6500685 Forward-Port-Of: odoo/enterprise#132009 Forward-Port-Of: odoo/enterprise#130429
Improves the new Marketing Automation app by preventing crashes, correcting customer enrollment from website sales, and ensuring campaign steps link to the right participants. These fixes make campaign setup and execution more reliable for users testing or running automated marketing flows.
Original PR description
This PR adds some fixes and feedbacks received during the testing of the new marketing_automation app. ### [FIX] marketing_automation: reinforce view_coordinates and view names This commit fixes…
This PR adds some fixes and feedbacks received during the testing of the new marketing_automation app. ### [FIX] marketing_automation: reinforce view_coordinates and view names This commit fixes issues that were introduced with the new marketing automation revamp. The calls to the view_coordinates field are reinforced to take into account a possible empty value. Some views were either wrongly renamed or no longer used to display server actions or trigger form views in the flow view. ### [FIX] marketing_automation: fix triggering_trace_id computation This commit fixes an issue with the computation of the triggering_trace_id field when generating children traces. Before, when creating the hash map to group all traces per activity and ids we used the field res_id. The issue is that if you have multiple traces that are using the same res_id, e.g. when testing participants, then you would have multiple traces on a specific key. Meaning that you would get crashes when trying to get the correct trace's ID. Now, instead of using a trace's res_id we use the participant_id directly. The idea is that for a specific activity you would have unique participants for each trace but each participant could have the same res_id. This way we ensure that when we create the children traces they get each their own correct triggering_trace_id. ### [FIX] marketing_automation_website_sale: fix participant enrollment This commit fixes an issue with the marketing_website_sale bridge and the way it enrolled participants. The issue was that no matter what the participant was never created it was simply caused by a wrong method override. Now, we override the correct method so that the enrollment can work as intended. task-6559148 Forward-Port-Of: odoo/enterprise#131559
Italian Split Payment taxes now use the correct VAT report placement, formula sign, and invoice labels. This helps Italian companies produce more accurate VAT reports and clearer customer invoices for SP tax rates.
Original PR description
The`SP` (Split Payment) taxes have incorrect configurations: - **Tax Grid Tags on `SP` Taxes**: The ve38 grid tag was incorrectly assigned to the tax line instead of the base line. - **`VE38` VAT…
The`SP` (Split Payment) taxes have incorrect configurations: - **Tax Grid Tags on `SP` Taxes**: The ve38 grid tag was incorrectly assigned to the tax line instead of the base line. - **`VE38` VAT Report Formula**: In Tax Report > VAT Report, the line `VE38 - Transactions with parties referred to in Article 17-ter` was using a negative formula `-ve38` and should be `ve38` - **Tax Group Invoice Label**: Updated the default label on invoices for the SP tax group to display 22% SP instead of 22%. Steps to reproduce: - Install `account` and `l10n_it` - Switch to IT company - Go to taxes and filter for `SP` taxes - The tax grid is wrong for the negative taxes since `ve38` should be in the base line instead of in the tax line - Go in the Tax report > VE VAT Report - The line `VE38 - Transactions with parties referred to in Article 17-ter` has a negative formula `-ve38`, should be positive `ve38` - The label on invoices of the tax group should be `4% SP`, `5% SP`, `10% SP` not `4%` etc. References: https://www.informazionefiscale.it/IMG/pdf/dichiarazione_modello_iva_2026_agenzia_delle_entrate.pdf <img width="1413" height="141" alt="immagine" src="https://github.com/user-attachments/assets/7fa15859-beaa-4345-bf81-fedc3f0af2fa" /> https://fiscomania.com/quadro-ve-della-dichiarazione-iva/ <img width="705" height="154" alt="immagine" src="https://github.com/user-attachments/assets/4f23b407-0e4d-4104-9695-f9891ccfd2f2" /> Ticket [link](https://www.odoo.com/odoo/project.task/6543520) opw-6543520 Forward-Port-Of: odoo/odoo#287238
Credit notes for invoices already accepted in Poland's KSeF system now export the correct KSeF reference information. This prevents the XML from wrongly marking the original invoice as issued outside KSeF, helping businesses stay compliant with official Polish e-invoicing rules.
Original PR description
### Issue before this commit: When generating a credit note for an invoice already accepted in the Polish KSeF system, the exported XML incorrectly includes the <NrKSeFN>1</NrKSeFN> tag. This tag…
### Issue before this commit: When generating a credit note for an invoice already accepted in the Polish KSeF system, the exported XML incorrectly includes the <NrKSeFN>1</NrKSeFN> tag. This tag falsely indicates that the original invoice was issued outside of KSeF, and the official KSeF number of the corrected invoice is entirely omitted from the file. ### Steps to reproduce the issue: 1. Download Accounting and l10n_pl 2. Go to Settings > Polish Localization > Insert certificate 3. Go to Invoices > Create an invoice > Send it to KSeF 4. Create a credit note for that invoice, reverse it and send it to KSeF 5. Tag <NrKSeFN>1</NrKSeFN> should not be there ### Cause of the issue: The tag <NrKSeFN>1</NrKSeFN> is emitted in every case without any rule handling it. ### Reason to introduce the fix: To comply with the official FA(3) logical structure rules. According to the specifications, if the corrected invoice was issued and accepted in KSeF, the XML must include the <NrKSeF>1</NrKSeF> flag and additionally provide the original KSeF number in the <NrKSeFFaKorygowanej> field. Otherwise, if the original invoice was issued outside of KSeF, the system must enter "1" in the <NrKSeFN> field and strictly omit the <NrKSeF> and <NrKSeFFaKorygowanej> fields. <img width="866" height="981" alt="image" src="https://github.com/user-attachments/assets/53b42f9f-aaab-4642-be38-2a5abc1d8539" /> opw-6541941 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#288286
Fixed an issue where some form values in quotation header or footer PDFs could disappear when generating PDF quotes. This ensures sales documents using advanced PDF form structures keep the expected customer-facing information after PDF processing.
Original PR description
Issue: --- When a quotation header/footer PDF has a hierarchical AcroForm field, the value set for that field is silently dropped from the generated PDF Quote when running on pypdf 5.4.0. Steps to…
Issue: --- When a quotation header/footer PDF has a hierarchical AcroForm field, the value set for that field is silently dropped from the generated PDF Quote when running on pypdf 5.4.0. Steps to reproduce: 1- Using a python 3.13 env, install requirements.txt (or otherwise run with pypdf==5.4.0 instead of PyPDF2). 2- Upload a header/footer PDF whose form field is a hierarchical field (`/T`/`/FT`/`/V` on the parent, not on the widget itself). The attachment from the ticket can be used as a sample to reproduce the bug. 3- Create a SO and select that document in the Quote Builder tab. 4- Print -> PDF Quote. 5- The value bound to that field does not appear in the printed PDF. Cause: --- After https://github.com/odoo/odoo/commit/4b02fbd717f62dd5345dad3ffb8d428c1c180007 `_add_pages_to_writer` renames the parent `/Field` object's `/T` when the widget itself has none. PyPDF2's `addPage` inserted the reader's page as is, keeping the widget's `/Parent`. pypdf 5.4.0 deep clones the page instead and ignores `/Parent` at every depth, so the widget loses the link to that field. It ends up with neither `/T` nor `/FT`, hence nothing matches the value mapping. Fix: --- Merge the field into its widget annotations instead: copy the prefixed `/T` and the inheritable keys onto each of them, then drop `/Parent`. The field's own `/T` is left untouched, so a field owning several widgets is filled on all of them. opw-6508728 Forward-Port-Of: odoo/odoo#287910 Forward-Port-Of: odoo/odoo#286186
This fix prevents spreadsheet version history from being rebuilt from the wrong starting point when older revision data was altered by migration cleanup. It protects users from restoring a corrupted spreadsheet version and helps preserve spreadsheet data integrity.
Original PR description
…heet history Some spreadsheet can end up in a corrupted history state Original Data ⮕ no revision (XX) ⮕ Snapshot ⮕ Active Revisions and where the original data differ from the snapshot. XX: can…
…heet history Some spreadsheet can end up in a corrupted history state Original Data ⮕ no revision (XX) ⮕ Snapshot ⮕ Active Revisions and where the original data differ from the snapshot. XX: can occur after the script added https://github.com/odoo/upgrade/issues/6340. The migration script is supposed to rewrite the history of the spreadsheet when there are holes in the archived revisions continuity (eg. the history was original Data ⮕ rev **A** ⮕ rev **B** ⮕ rev **C** ⮕ snapshot ⮕ rev **D** and user deleted rev **B** for instance, the script deletes **A** and **C** and marks **D** as the very first revision). Version history was designed with the idea to replay every single revision that existed since the creation of the spreadsheet and apply it to the original data, and in case of missing revisions, in our example, B is missing, we detect the lack of continuity, we start from the snapshot, and replay every single revision since that snapshot. When the migration fixes the continuity, by deleting all the old revisions, and changing their order, we can no longer detect the lack of continuity and end up replay every available revision to the original data ,even though they are based on the snapshot. In that scenario, since the revisions will be applied on the original data but since they are based on the state of the snapshot only, the final state of the spreadsheet will be corrupted since a part of the . If a user then decides to restore the spreadsheet to the version they see in the version history (which is corrupted as mentioned) and the last snapshot is overwritten with the corrupted state, effectively breaking the spreadsheet. With this revision, we add a detection of this corrupted history state, in which case we enforce the history to be replayed from the snapshot and not the original data. Task-6533708 Forward-Port-Of: odoo/enterprise#132033 Forward-Port-Of: odoo/enterprise#130649