Daily updates from Odoo
Navigate
Branch
Saturday, August 8, 2026
83 changes
9 changes
Enhancements to existing features
Calendar events are now matched to the right project or task using the event's linked record before falling back to partner history. This makes suggested timesheets more accurate and reduces manual corrections for users who track time from calendar entries.
Original PR description
…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 Forward-Port-Of: odoo/enterprise#123158
Resolved issues and error corrections
Payroll warning information is now consistently visible in payslip and pay run list views instead of appearing as an unnamed optional column. This improves clarity for payroll users and prevents confusing empty entries in the column selection menu.
Original PR description
Currently, in the payslip and payrun view, we can see empty label in optional dropdown. Having empty label isn't UX friendly. This empty label is refered to payslip warnings. In this PR expected to change visibility of warning fields, The visibility must be always visible and the field is no longer optional. This condition applies to PayRun and Paylist ListViews. task-6424657 Forward-Port-Of: odoo/enterprise#127224 Forward-Port-Of: odoo/enterprise#125860
The exchange rate update link for the Romanian National Bank has been changed to the new official domain. This prevents future disruption to automatic currency rate updates after the old address stops serving XML files.
Original PR description
As of 6 August 2026, the XML files used by software applications to retrieve daily exchange rates will no longer be available directly through addresses on the www.bnr.ro domain and will be accessible exclusively via the curs.bnr.ro subdomain. The XML file names will remain unchanged; only the access domain will be modified. no-task Forward-Port-Of: odoo/enterprise#127177
This update fixes a Swiss payroll transmission issue where a required value was not being recorded in the payroll logs. This helps payroll teams keep more complete records for compliance checks and troubleshooting.
Original PR description
Forward-Port-Of: odoo/enterprise#127241
`_selection_target_model()` searched all records of ir_model and due to some prefetch issues, multiple queries ran depending on the number of models in db. By using search_fetch we eliminate this. Partial backport of odoo/odoo#281215 Forward-Port-Of: odoo/odoo#281229
Original PR description
`_selection_target_model()` searched all records of ir_model and due to some prefetch issues, multiple queries ran depending on the number of models in db. By using search_fetch we eliminate this. Partial backport of odoo/odoo#281215 Forward-Port-Of: odoo/odoo#281229
Before this commit, the unread badge of the Chat action could stay empty after a click on "Mark as Unread" in the meeting view: FAILED: [17/24] Tour discuss.meeting_view_public_tour Step .o-mail-Meeting [title='Chat']:has(.badge:contains(1)) This happens because a mark as read and a mark as unread write the same fields of the channel member in two requests, and the server applies them in the order it receives them, not the order they are sent. Under CI load, a mark as read sent be
Original PR description
Before this commit, the unread badge of the Chat action could stay empty after a click on "Mark as Unread" in the meeting view:
FAILED: [17/24] Tour discuss.meeting_view_public_tour
Step .o-mail-Meeting [title='Chat']:has(.badge:contains(1))
This happens because a mark as read and a mark as unread write the same fields of the channel member in two requests, and the server applies them in the order it receives them, not the order they are sent. Under CI load, a mark as read sent before the click reached the server after the mark as unread, marking the member read again and hiding the badge through its bus push.
This commit requests the mark as unread through the queue of the mark
as read, which sends one request at a time.
This also drops the check the mark as read made against a mark as unread requested in between, as the queue keeps only the last request and replaces the waiting one.
https://runbot.odoo.com/odoo/error/944432
Forward-Port-Of: odoo/odoo#280946Steps to reproduce ------------------ 1. Install `l10n_pe_pos`. 2. Create a contact with the identification type DNI and a number. 3. Sell a product to this contact and print the receipt. -> the receipt shows "RUC" in front of the number, even though the number is a DNI and not a RUC. Why it's happening ------------------ Since `aeaca097ae39` the number of the contact is printed with a label in front of it, before there was no label at all. This label is the `vat_label` of the country,
Original PR description
Steps to reproduce ------------------ 1. Install `l10n_pe_pos`. 2. Create a contact with the identification type DNI and a number. 3. Sell a product to this contact and print the receipt. -> the…
Steps to reproduce ------------------ 1. Install `l10n_pe_pos`. 2. Create a contact with the identification type DNI and a number. 3. Sell a product to this contact and print the receipt. -> the receipt shows "RUC" in front of the number, even though the number is a DNI and not a RUC. Why it's happening ------------------ Since `aeaca097ae39` the number of the contact is printed with a label in front of it, before there was no label at all. This label is the `vat_label` of the country, so "RUC" for Peru. But in Peru each contact can have a different identifier, and the type is on the contact in `l10n_latam_identification_type_id`. The fix ------- In `l10n_pe_pos` we set `partner_vat_label` with the name of the identification type of the contact. If the contact has no identification type we keep the number alone. Before vs After for a customer identified with DNI ------------------------------------------------- <img width="465" height="203" alt="Capture d’écran 2026-07-30 à 14 45 17" src="https://github.com/user-attachments/assets/85c921df-c1fd-430b-b4e6-341bc183bd61" /> <img width="467" height="253" alt="Capture d’écran 2026-07-30 à 14 49 36" src="https://github.com/user-attachments/assets/3ac243c6-04fe-47a4-a662-c59b88276db7" /> opw-6422619 Forward-Port-Of: odoo/odoo#279409
Otherwise using the "Update Apps List" wizard (`base.action_view_base_module_update`) and then trying to `_get` the new module may not work because `_get_id` is `ormcache`ed. To reproduce: 1. Install `account_peppol` and `l10n_fr` 2. Delete the `l10n_fr_pdp` module from the apps 3. Go to the settings and click "Activate Electronic Invoicing" 4. Make sure "France FRCTC Electronic Address" is selected 5. Click on "Activate Peppol (Demo)" 6. Click on "Update App List" in the warning 7. Cl
Original PR description
Otherwise using the "Update Apps List" wizard (`base.action_view_base_module_update`) and then trying to `_get` the new module may not work because `_get_id` is `ormcache`ed. To reproduce: 1. Install `account_peppol` and `l10n_fr` 2. Delete the `l10n_fr_pdp` module from the apps 3. Go to the settings and click "Activate Electronic Invoicing" 4. Make sure "France FRCTC Electronic Address" is selected 5. Click on "Activate Peppol (Demo)" 6. Click on "Update App List" in the warning 7. Click on "Update" 8. Start over at step 3. and the same warning appears again, but the module can be found in the "Apps" already. Everything works fine after a server restart. task-None Forward-Port-Of: odoo/odoo#281299 Forward-Port-Of: odoo/odoo#280938
### Issue before this commit: When generating ZUGFeRD or Factur-X electronic invoices, including an HTML hyperlink (such as an email or website) in the document layout caused the final PDF to fail PDF/A validation. Portals would reject the file with the error: "An annotation dictionary does not contain the key F". ### Steps to reproduce the issue: 1. Download Accounting and l10n_de 2. Go to Contacts > set Tax ID for company Bloem GmbH and also for DE company 3. Activate ZUGFeRD from setti
Original PR description
### Issue before this commit: When generating ZUGFeRD or Factur-X electronic invoices, including an HTML hyperlink (such as an email or website) in the document layout caused the final PDF to fail…
### Issue before this commit: When generating ZUGFeRD or Factur-X electronic invoices, including an HTML hyperlink (such as an email or website) in the document layout caused the final PDF to fail PDF/A validation. Portals would reject the file with the error: "An annotation dictionary does not contain the key F". ### Steps to reproduce the issue: 1. Download Accounting and l10n_de 2. Go to Contacts > set Tax ID for company Bloem GmbH and also for DE company 3. Activate ZUGFeRD from settings 4. Go to settings and click on Configure Document Layout and insert something like <a href="mailto:info@company.de_skr03example.com"> info@company.de_skr03example.com</a> into the footer 5. Create an invoice to Bloem GmbH and send it through ZUGFeRD 6. Download PDF and upload it on https://www.portinvoice.com/ 7. See error: An annotation dictionary does not contain the key F. With the exception of annotation dictionaries whose subtype value is Popup, all annotation dictionaries must contain the key F. ### Cause of the issue: The underlying PDF generation engine creates hyperlinks as PDF annotations but omits the /F (Flags) key. During Odoo's PDF/A conversion process, these annotations were left unmodified. This violates the strict PDF/A specification, which mandates that all non-Popup annotations must explicitly define the /F key. ### Reason to introduce the fix: This fix ensures full PDF/A compliance by iterating through all page annotations and injecting the missing /F key for any annotation that is not a Popup. This allows users to safely include clickable links in their invoice templates without breaking electronic document validation. opw-6388212 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281275 Forward-Port-Of: odoo/odoo#279024
9 changes
Enhancements to existing features
Calendar events are now matched to the right project or task using the event's linked record before falling back to partner history. This makes suggested timesheets more accurate and reduces manual corrections for users tracking time from calendar events.
Original PR description
…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
Resolved issues and error corrections
The Timesheet Assistant now avoids creating away-from-keyboard suggestions during always-active activities such as online meetings. This keeps meeting time grouped correctly, improves duration accuracy, and fixes the Google Meet description shown to users.
Original PR description
## Previous Behavior Before this PR: Users could have their always-active event split by an AFK event inside of Timesheet Assistant. AFK event durations were also inaccurate, and the Google Meet…
## Previous Behavior Before this PR: Users could have their always-active event split by an AFK event inside of Timesheet Assistant. AFK event durations were also inaccurate, and the Google Meet description was incorrect. ## Steps to Reproduce: 1. Generate an always-active event (e.g., join a meeting in Google Meet). 2. Generate non-key events (e.g., visit a website without an ActivityWatch rule). 3. Go AFK. 4. Generate a new non-key event. 5. The Timesheet Assistant will show three suggestions in the following order: an always-active suggestion, an AFK suggestion, and another always-active suggestion for the same activity. ## New Expected Behavior After this PR: The Timesheet Assistant now blocks the creation of AFK suggestions when the previous key event is marked as always-active. AFK event durations have been updated to ensure their values are accurate. The Google Meet description has also been corrected. task-[6431526](https://www.odoo.com/odoo/project/4105/tasks/6431526)
The Romanian National Bank exchange rate feed now uses the new official domain required from August 2026. This keeps automatic currency rate updates working without interruption for companies relying on Romanian exchange rates.
Original PR description
As of 6 August 2026, the XML files used by software applications to retrieve daily exchange rates will no longer be available directly through addresses on the www.bnr.ro domain and will be accessible exclusively via the curs.bnr.ro subdomain. The XML file names will remain unchanged; only the access domain will be modified. no-task Forward-Port-Of: odoo/enterprise#127177
Financial reports now show the expected current month or quarter when opened with a yearly default date filter. Custom comparison dates also refresh immediately and no longer default to future dates, reducing confusion when reviewing current-year performance.
Original PR description
When opening reports with `default_opening_date_filter='this_year'`(e.g., P&L, Partner Ledger), the date filter dropdown showed incorrect defaults for non-selected period types: - Month showed the…
When opening reports with `default_opening_date_filter='this_year'`(e.g., P&L, Partner Ledger), the date filter dropdown showed incorrect defaults for non-selected period types: - Month showed the last month of the fiscal year (e.g., December) instead of the current month - Quarter showed Q4 instead of the current quarter This happened because `initDateFilterState()` used the backend's `date_to` (fiscal year end) as the reference for computing all filter periods. For `this_year`, `date_to` is the year-end date (e.g., 2026-12-31), so `computePeriodRange()` for month/quarter returned periods containing that date rather than today's date. Reports with `this_month` or `today` defaults were unaffected because their `date_to` is naturally close to today. Now, non-selected filters use today as their reference date on initial load whenever today falls within the report period, while the selected filter continues to use the backend's `date_to`, preserving the alignment behavior introduced in the date filter refactor (https://github.com/odoo/enterprise/commit/40484f985f511edd7ba2ae759ce63ef564bcf1f7). Additionally, selecting the custom comparison filter now triggers an immediate reload so its default date range is recomputed by the backend. The custom comparison range is initialized using the current fiscal year up to today, capping its end date to today instead of inheriting the report's `date_to`, which could otherwise default to a future date for yearly reports. task-6229588 Forward-Port-Of: odoo/enterprise#121638
`_selection_target_model()` searched all records of ir_model and due to some prefetch issues, multiple queries ran depending on the number of models in db. By using search_fetch we eliminate this. Partial backport of odoo/odoo#281215 Forward-Port-Of: odoo/odoo#281229
Original PR description
`_selection_target_model()` searched all records of ir_model and due to some prefetch issues, multiple queries ran depending on the number of models in db. By using search_fetch we eliminate this. Partial backport of odoo/odoo#281215 Forward-Port-Of: odoo/odoo#281229
Before this commit, the unread badge of the Chat action could stay empty after a click on "Mark as Unread" in the meeting view: FAILED: [17/24] Tour discuss.meeting_view_public_tour Step .o-mail-Meeting [title='Chat']:has(.badge:contains(1)) This happens because a mark as read and a mark as unread write the same fields of the channel member in two requests, and the server applies them in the order it receives them, not the order they are sent. Under CI load, a mark as read sent be
Original PR description
Before this commit, the unread badge of the Chat action could stay empty after a click on "Mark as Unread" in the meeting view:
FAILED: [17/24] Tour discuss.meeting_view_public_tour
Step .o-mail-Meeting [title='Chat']:has(.badge:contains(1))
This happens because a mark as read and a mark as unread write the same fields of the channel member in two requests, and the server applies them in the order it receives them, not the order they are sent. Under CI load, a mark as read sent before the click reached the server after the mark as unread, marking the member read again and hiding the badge through its bus push.
This commit requests the mark as unread through the queue of the mark
as read, which sends one request at a time.
This also drops the check the mark as read made against a mark as unread requested in between, as the queue keeps only the last request and replaces the waiting one.
https://runbot.odoo.com/odoo/error/944432
Forward-Port-Of: odoo/odoo#280946Steps to reproduce ------------------ 1. Install `l10n_pe_pos`. 2. Create a contact with the identification type DNI and a number. 3. Sell a product to this contact and print the receipt. -> the receipt shows "RUC" in front of the number, even though the number is a DNI and not a RUC. Why it's happening ------------------ Since `aeaca097ae39` the number of the contact is printed with a label in front of it, before there was no label at all. This label is the `vat_label` of the country,
Original PR description
Steps to reproduce ------------------ 1. Install `l10n_pe_pos`. 2. Create a contact with the identification type DNI and a number. 3. Sell a product to this contact and print the receipt. -> the…
Steps to reproduce ------------------ 1. Install `l10n_pe_pos`. 2. Create a contact with the identification type DNI and a number. 3. Sell a product to this contact and print the receipt. -> the receipt shows "RUC" in front of the number, even though the number is a DNI and not a RUC. Why it's happening ------------------ Since `aeaca097ae39` the number of the contact is printed with a label in front of it, before there was no label at all. This label is the `vat_label` of the country, so "RUC" for Peru. But in Peru each contact can have a different identifier, and the type is on the contact in `l10n_latam_identification_type_id`. The fix ------- In `l10n_pe_pos` we set `partner_vat_label` with the name of the identification type of the contact. If the contact has no identification type we keep the number alone. Before vs After for a customer identified with DNI ------------------------------------------------- <img width="465" height="203" alt="Capture d’écran 2026-07-30 à 14 45 17" src="https://github.com/user-attachments/assets/85c921df-c1fd-430b-b4e6-341bc183bd61" /> <img width="467" height="253" alt="Capture d’écran 2026-07-30 à 14 49 36" src="https://github.com/user-attachments/assets/3ac243c6-04fe-47a4-a662-c59b88276db7" /> opw-6422619 Forward-Port-Of: odoo/odoo#279409
Otherwise using the "Update Apps List" wizard (`base.action_view_base_module_update`) and then trying to `_get` the new module may not work because `_get_id` is `ormcache`ed. To reproduce: 1. Install `account_peppol` and `l10n_fr` 2. Delete the `l10n_fr_pdp` module from the apps 3. Go to the settings and click "Activate Electronic Invoicing" 4. Make sure "France FRCTC Electronic Address" is selected 5. Click on "Activate Peppol (Demo)" 6. Click on "Update App List" in the warning 7. Cl
Original PR description
Otherwise using the "Update Apps List" wizard (`base.action_view_base_module_update`) and then trying to `_get` the new module may not work because `_get_id` is `ormcache`ed. To reproduce: 1. Install `account_peppol` and `l10n_fr` 2. Delete the `l10n_fr_pdp` module from the apps 3. Go to the settings and click "Activate Electronic Invoicing" 4. Make sure "France FRCTC Electronic Address" is selected 5. Click on "Activate Peppol (Demo)" 6. Click on "Update App List" in the warning 7. Click on "Update" 8. Start over at step 3. and the same warning appears again, but the module can be found in the "Apps" already. Everything works fine after a server restart. task-None Forward-Port-Of: odoo/odoo#281299 Forward-Port-Of: odoo/odoo#280938
You'll need two users : - Internal User A that can create projects - User B with a granted portal access Optionnal third user to compare the flows : - Internal User B that can create tasks in a porject - With User A, create a new project with atleast a single stage - Go to the project settings - Make sure that Visibility is set to : "All internal users and invited portal users" - Click on Share Project - Add User B as a new Collaborator with the Edit acess mode - Confirm by clic
Original PR description
You'll need two users : - Internal User A that can create projects - User B with a granted portal access Optionnal third user to compare the flows : - Internal User B that can create tasks in a…
You'll need two users : - Internal User A that can create projects - User B with a granted portal access Optionnal third user to compare the flows : - Internal User B that can create tasks in a porject - With User A, create a new project with atleast a single stage - Go to the project settings - Make sure that Visibility is set to : "All internal users and invited portal users" - Click on Share Project - Add User B as a new Collaborator with the Edit acess mode - Confirm by clicking on Share Project - Still in the project settings, click on the blue user icon in the top right to edit the Followers : - Make sure you are following the project - Click on the edit button and make sure Task Created is checked Optionnal for easiness of testing : - Go to the User A settings and in Preferences > Notifications : In Odoo - Log in with User B (in a new incognito tab on the side is best) - Go to Projects > The project that has been shared - Create a new task No notification is sent to User A. If the same flow is done using User C, then a notification is correctly sent. The fields that determine to which users the notifications are sent to is `message_follower_ids`. In our case, the value of that field does not contain User A, so no notifcation is sent to them. The method responsible for assigning values to that field is `_message_auto_subscribe()` which adds follower using subtypes parent relationship. The parent subtype of tasks are projects. So, essentially, we look for followers of the parent project, and see if we can add them to our task. Before proceeding with the assignation, we check that the parent subtype's field was actually edited : https://github.com/odoo/odoo/blob/ea18f34a48d61350f80c79894bef66bf02840bfc/addons/mail/models/mail_thread.py#L4778-L4781 So we look that `updated_values` contains "project_id". `updated_values` is created by the the `mail_thread` create method by joining the values in `vals_list` and the context default variables. In our case, this should be enough since `default_project_id` is provided when creating a task : https://github.com/odoo/odoo/blob/ea18f34a48d61350f80c79894bef66bf02840bfc/addons/mail/models/mail_thread.py#L340-L344 But, a bit before this, the task create method edits the context to replace 'default_project_id' by 'default_create_in_project_id' : https://github.com/odoo/odoo/blob/ea18f34a48d61350f80c79894bef66bf02840bfc/addons/project/models/project_task.py#L1102-L1109 So we do not detect that `project_id` has been changed and don't actually add the followers. We remove the custom 'default_create_in_project_id` context opw-6026932 Forward-Port-Of: odoo/odoo#278824 Forward-Port-Of: odoo/odoo#278353
16 changes
Enhancements to existing features
Receipt printer selection now uses the same broader matching rules as preparation printers. This helps point-of-sale setups find compatible IoT printers more consistently and reduces configuration friction.
Original PR description
In odoo/enterprise#124306, we removed the subtype from the printer domain, but only for preparation printers. We also update it for receipt printers. Forward-Port-Of: odoo/enterprise#127142 Forward-Port-Of: odoo/enterprise#125648
Timesheet users can now select multiple assistant suggestions by holding the mouse button and moving across them, making batch creation or removal faster. The change also prevents Ctrl-clicking a suggestion from accidentally opening a new Odoo page, reducing disruption during timesheet entry.
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
Resolved issues and error corrections
Uruguay electronic delivery guide PDFs now correctly include a separate addenda page when the notes are too long for the standard form. This prevents important delivery information from being omitted in official printed documents.
Original PR description
**Description** When printing the legal PDF of a CFE, the report can request a dedicated addenda page (`adenda=true` report parameter) when the addenda does not fit in the small box of the standard…
**Description** When printing the legal PDF of a CFE, the report can request a dedicated addenda page (`adenda=true` report parameter) when the addenda does not fit in the small box of the standard report (roughly 6 lines of 140 characters). `l10n_uy_edi_document._get_report_params()` computed the addenda by calling `self.move_id._l10n_uy_edi_get_addenda()` directly. For e-remito EDI documents created from stock pickings, `move_id` is not set, so the addenda was always empty and the dedicated addenda page was never requested for delivery guides. **Changes** - Resolve the addenda from the document origin record: reuse the existing `_get_origin_record()` abstraction. Add it on `l10n_uy_edi.document` (returns the move) and let `l10n_uy_edi_stock` extend it to fall back to `picking_id`; `_get_report_params()` now reads the addenda through it. - Remove a no-op `_get_pdf()` override in `l10n_uy_edi_stock`. - Add a unit test covering the dedicated addenda page threshold (6 lines x 140 chars) for delivery guides. **Note** This PR replaces branch `adhoc-dev:18.0-t-stock-edi-addenda-fix-kz` (original authorship preserved); resubmitted from a new branch to keep follow-up and tracking with the current maintainer. Forward-Port-Of: odoo/enterprise#124539
This fix stops Approval Request status calculations from trying to send notifications while a form is only being previewed or updated in the background. It prevents crashes during form changes, especially when Studio fields link to approved or refused approval requests, making approval-related workflows more reliable.
Original PR description
**Before this change** We have the potential to attempt to send a notification email from virtual records created by our `BaseModel.new()` method. This can happen during an `onchange` request, given…
**Before this change** We have the potential to attempt to send a notification email from virtual records created by our `BaseModel.new()` method. This can happen during an `onchange` request, given that we'll be working with a virtual "snapshot" record to recompute potentially changed values for our origin record after a change to one or more values. This issue manifests when using Studio to attach a many2many field to a form view, where the related model is "Approval Request". If an approval request record in either the "Approved" or "Refused" state is attached to our record via this new Studio field, any `onchange` requests will trigger this bug. This is because we can't send messages on a virtual record. **After this change** Prevent the creation and sending of a message if we are computing the request status of a virtual `approval.request()` record. The field `request_status` on this model is computed and stored, but the fact that it is a computed field means that it must be recomputed for a virtual record, even if the origin record already has a stored `request_status`. Thus, we may need to compute a `request_status` value for an ephemeral "snapshot" record. Though the issue only manifests for the "Approved" and "Refused" states, this PR expands on a test that covers every approval request state. opw-6390453 Forward-Port-Of: odoo/enterprise#125374
Dutch VAT correction submissions will now be sent with the correct OBSUP message type instead of being treated as regular VAT reports. This prevents routing errors in Digipoort and helps ensure correction filings reach the right destination.
Original PR description
Description of the issue this commit addresses: VAT corrections are sent to Digipoort as regular VAT reports, causing routing errors. --- Desired behavior after this commit is merged: This commit sends VAT corrections using the OBSUP message type. --- opw-6353166 Forward-Port-Of: odoo/enterprise#127235
This fix ensures the Swiss payroll ELM transmission process correctly records the minimum income value in payroll logs. This helps payroll teams and administrators review transmissions more reliably and reduces confusion during checks or audits.
Original PR description
Forward-Port-Of: odoo/enterprise#127241
This fixes an issue where signatures could disappear from downloaded signed PDFs when the original document had unusual page positioning from another PDF tool. Signed documents now match the preview, helping users trust that completed agreements contain all visible fields.
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#121960
The live currency rate update has been adjusted to use the Romanian National Bank's new required web address. This helps ensure daily exchange rates continue to update automatically after the old address stops working in August 2026.
Original PR description
As of 6 August 2026, the XML files used by software applications to retrieve daily exchange rates will no longer be available directly through addresses on the www.bnr.ro domain and will be accessible exclusively via the curs.bnr.ro subdomain. The XML file names will remain unchanged; only the access domain will be modified. no-task Forward-Port-Of: odoo/enterprise#127177
The test `editing s_popup, then closing it, then undo show it again` had a few fails in CI: the `fa-eye` was not set as expected. This commit adds a `waitSidebarUpdated` call just before to ensure owl has no pending rendering when checking the eye. runbot-242292 Forward-Port-Of: odoo/odoo#263490
Original PR description
The test `editing s_popup, then closing it, then undo show it again` had a few fails in CI: the `fa-eye` was not set as expected. This commit adds a `waitSidebarUpdated` call just before to ensure owl has no pending rendering when checking the eye. runbot-242292 Forward-Port-Of: odoo/odoo#263490
Currently, people can get infinite loop in the cron that fetches messages from the ppf, as we don't catch the exception that may happen. At least catch them, so we can send an ack opw-6440955 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281170
Original PR description
Currently, people can get infinite loop in the cron that fetches messages from the ppf, as we don't catch the exception that may happen. At least catch them, so we can send an ack opw-6440955 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281170
### Issue before this commit: When generating ZUGFeRD or Factur-X electronic invoices, including an HTML hyperlink (such as an email or website) in the document layout caused the final PDF to fail PDF/A validation. Portals would reject the file with the error: "An annotation dictionary does not contain the key F". ### Steps to reproduce the issue: 1. Download Accounting and l10n_de 2. Go to Contacts > set Tax ID for company Bloem GmbH and also for DE company 3. Activate ZUGFeRD from setti
Original PR description
### Issue before this commit: When generating ZUGFeRD or Factur-X electronic invoices, including an HTML hyperlink (such as an email or website) in the document layout caused the final PDF to fail…
### Issue before this commit: When generating ZUGFeRD or Factur-X electronic invoices, including an HTML hyperlink (such as an email or website) in the document layout caused the final PDF to fail PDF/A validation. Portals would reject the file with the error: "An annotation dictionary does not contain the key F". ### Steps to reproduce the issue: 1. Download Accounting and l10n_de 2. Go to Contacts > set Tax ID for company Bloem GmbH and also for DE company 3. Activate ZUGFeRD from settings 4. Go to settings and click on Configure Document Layout and insert something like <a href="mailto:info@company.de_skr03example.com"> info@company.de_skr03example.com</a> into the footer 5. Create an invoice to Bloem GmbH and send it through ZUGFeRD 6. Download PDF and upload it on https://www.portinvoice.com/ 7. See error: An annotation dictionary does not contain the key F. With the exception of annotation dictionaries whose subtype value is Popup, all annotation dictionaries must contain the key F. ### Cause of the issue: The underlying PDF generation engine creates hyperlinks as PDF annotations but omits the /F (Flags) key. During Odoo's PDF/A conversion process, these annotations were left unmodified. This violates the strict PDF/A specification, which mandates that all non-Popup annotations must explicitly define the /F key. ### Reason to introduce the fix: This fix ensures full PDF/A compliance by iterating through all page annotations and injecting the missing /F key for any annotation that is not a Popup. This allows users to safely include clickable links in their invoice templates without breaking electronic document validation. opw-6388212 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279024
Sometimes the default_state remains in the context from a past action and when the subcontractor fills its components consumptions it will directly modify the quant's quantity. This trigger the automatic rules and generate an unwanted picking opw-6109661 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of:
Original PR description
Sometimes the default_state remains in the context from a past action and when the subcontractor fills its components consumptions it will directly modify the quant's quantity. This trigger the automatic rules and generate an unwanted picking opw-6109661 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280930 Forward-Port-Of: odoo/odoo#280733
**Steps to reproduce:** 1. Install Accounting and l10n_be and switch to the Belgian company 2. In the settings, set the discount account (`708000`) on Customer Invoices under "Default Accounts" and enable analytic accounting 3. Go to [Accounting -> Configuration -> Analytic Accounts] and create 4 new accounts with "Project" plan (i.e 1,2,3,4) 4. Create a new invoice with two lines, each having 2 of the analytic accounts with 50% each. 5. Set the price to 1000 and a 10% discount for each lin
Original PR description
**Steps to reproduce:** 1. Install Accounting and l10n_be and switch to the Belgian company 2. In the settings, set the discount account (`708000`) on Customer Invoices under "Default Accounts" and…
**Steps to reproduce:** 1. Install Accounting and l10n_be and switch to the Belgian company 2. In the settings, set the discount account (`708000`) on Customer Invoices under "Default Accounts" and enable analytic accounting 3. Go to [Accounting -> Configuration -> Analytic Accounts] and create 4 new accounts with "Project" plan (i.e 1,2,3,4) 4. Create a new invoice with two lines, each having 2 of the analytic accounts with 50% each. 5. Set the price to 1000 and a 10% discount for each line then save. 6. Edit the second line and set the discount to 20%. 7. Open the Journal Items tab **Issue:** - When an invoice contains multiple lines with analytic distributions, changing the discount percentage on any line other than the first fails to correctly update the analytic distribution percentages on the corresponding discount journal items. - The analytic account distribution splits the percentage evenly across both accounts event if they are not split 50/50 **Why this happens:** - This occurred because `_compute_discount_allocation_needed` iterated over `self` to populate target changes. When only one line was modified, `self` contains that line only which is correctly updated with the new analytic distribution. Later in the execution in `_sync_dynamic_line`, particularly in https://github.com/odoo/odoo/blob/5a14360705a55f4d91edf39c936d7a5d8573044b/addons/account/models/account_move.py#L2263-L2274 The first line in `computed_needed` is what gets set in res, and subsequent lines only modify the field if it's monetary. So if the second invoice line is the one updated, it will never override the `analytic_distribution` with the updated values, leaving stale values in that field. - The code iterated directly over `line.analytic_distribution` dictionary keys (the account IDs) rather than its `.items()`. This caused it to ignore the individual percentage value splits (e.g. 60/40), accumulating the un-weighted full discount amount to each account ID. https://github.com/odoo/odoo/blob/5a14360705a55f4d91edf39c936d7a5d8573044b/addons/account/models/account_move_line.py#L1044-L1052 **Fix:** - Change the processing loop inside `_compute_discount_allocation_needed` from `self` to `self.move_id.line_ids` to calculate the correct `analytic_distribution` across all records. - Applying the factored weight ratio (`amount * (percentage / 100.0)`) to `distribution_totals` opw-6362084 Forward-Port-Of: odoo/odoo#280302 Forward-Port-Of: odoo/odoo#275070
In _validate_amount(), setting a "Percentage of balance" line to 0 raises "Statement line percentage can't be 0", and setting a "Percentage of statement line" to 0 raises "Balance percentage can't be 0". Align each error message with the amount type being validated. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280399 Forward-Port-Of: odoo/odoo#269393
Original PR description
In _validate_amount(), setting a "Percentage of balance" line to 0 raises "Statement line percentage can't be 0", and setting a "Percentage of statement line" to 0 raises "Balance percentage can't be 0". Align each error message with the amount type being validated. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280399 Forward-Port-Of: odoo/odoo#269393
Otherwise using the "Update Apps List" wizard (`base.action_view_base_module_update`) and then trying to `_get` the new module may not work because `_get_id` is `ormcache`ed. To reproduce: 1. Install `account_peppol` and `l10n_fr` 2. Delete the `l10n_fr_pdp` module from the apps 3. Go to the settings and click "Activate Electronic Invoicing" 4. Make sure "France FRCTC Electronic Address" is selected 5. Click on "Activate Peppol (Demo)" 6. Click on "Update App List" in the warning 7. Cl
Original PR description
Otherwise using the "Update Apps List" wizard (`base.action_view_base_module_update`) and then trying to `_get` the new module may not work because `_get_id` is `ormcache`ed. To reproduce: 1. Install `account_peppol` and `l10n_fr` 2. Delete the `l10n_fr_pdp` module from the apps 3. Go to the settings and click "Activate Electronic Invoicing" 4. Make sure "France FRCTC Electronic Address" is selected 5. Click on "Activate Peppol (Demo)" 6. Click on "Update App List" in the warning 7. Click on "Update" 8. Start over at step 3. and the same warning appears again, but the module can be found in the "Apps" already. Everything works fine after a server restart. task-None Forward-Port-Of: odoo/odoo#281299 Forward-Port-Of: odoo/odoo#280938
Features or functions removed from Odoo
An outdated automated test for structured payment references was removed because the related behavior was intentionally changed in an earlier update. This keeps the accounting test suite aligned with the current, simpler reconciliation setup based on easier matching rules for users.
Original PR description
After merging pr #117256 the behavior for creating auto reconcile models for structured reference is no longer working so the test for checking that behavior should be removed. This was an FP request to use contains instead of regex in auto reconcile model creation because it was too complicated for users. no task id Forward-Port-Of: odoo/enterprise#126635
2 changes
Resolved issues and error corrections
The live currency rate connection for Romania has been updated to use the central bank's new required web address. This helps ensure daily exchange rates continue to update automatically after the old address stops serving these files.
Original PR description
As of 6 August 2026, the XML files used by software applications to retrieve daily exchange rates will no longer be available directly through addresses on the www.bnr.ro domain and will be accessible exclusively via the curs.bnr.ro subdomain. The XML file names will remain unchanged; only the access domain will be modified. no-task Forward-Port-Of: odoo/enterprise#127177
Otherwise using the "Update Apps List" wizard (`base.action_view_base_module_update`) and then trying to `_get` the new module may not work because `_get_id` is `ormcache`ed. To reproduce: 1. Install `account_peppol` and `l10n_fr` 2. Delete the `l10n_fr_pdp` module from the apps 3. Go to the settings and click "Activate Electronic Invoicing" 4. Make sure "France FRCTC Electronic Address" is selected 5. Click on "Activate Peppol (Demo)" 6. Click on "Update App List" in the warning 7. Cl
Original PR description
Otherwise using the "Update Apps List" wizard (`base.action_view_base_module_update`) and then trying to `_get` the new module may not work because `_get_id` is `ormcache`ed. To reproduce: 1. Install `account_peppol` and `l10n_fr` 2. Delete the `l10n_fr_pdp` module from the apps 3. Go to the settings and click "Activate Electronic Invoicing" 4. Make sure "France FRCTC Electronic Address" is selected 5. Click on "Activate Peppol (Demo)" 6. Click on "Update App List" in the warning 7. Click on "Update" 8. Start over at step 3. and the same warning appears again, but the module can be found in the "Apps" already. Everything works fine after a server restart. task-None Forward-Port-Of: odoo/odoo#281299 Forward-Port-Of: odoo/odoo#280938
2 changes
Resolved issues and error corrections
The Romanian National Bank exchange rate feed used for automatic currency updates now points to its new official web address. This prevents future update failures when the old address stops serving the files in August 2026.
Original PR description
As of 6 August 2026, the XML files used by software applications to retrieve daily exchange rates will no longer be available directly through addresses on the www.bnr.ro domain and will be accessible exclusively via the curs.bnr.ro subdomain. The XML file names will remain unchanged; only the access domain will be modified. no-task Forward-Port-Of: odoo/enterprise#127177
This fix ensures Belgian payroll declarations report the correct mobility budget balance when it is paid after the employee's current setup no longer includes a mobility budget. It uses the previous quarter's information instead of reporting zero, helping avoid incorrect social security declarations.
Original PR description
When the mobility budget balance is paid on a version that no longer carries a mobility budget, fall back to the previous quarter's version to declare the correct amount instead of 0. Task-6384786
2 changes
Resolved issues and error corrections
The live currency rate update service now uses the Romanian National Bank's new curs.bnr.ro domain. This keeps automated exchange rate updates working after the old www.bnr.ro access path is retired in August 2026.
Original PR description
As of 6 August 2026, the XML files used by software applications to retrieve daily exchange rates will no longer be available directly through addresses on the www.bnr.ro domain and will be accessible exclusively via the curs.bnr.ro subdomain. The XML file names will remain unchanged; only the access domain will be modified. no-task Forward-Port-Of: odoo/enterprise#127177
On python 3.10.12 `test_export_translatable_resources` fails. This is fixed in this commit build-944659 I only tested it on 17.0 since we do not seem to have the build error on higher versions. But the minimum python version is 3.10 until [excluding saas-19.1](https://github.com/odoo/odoo/blob/11ee42b4bf70a1008b06d13a48263e42c381aeed/odoo/release.py#L39) Forward-Port-Of: odoo/odoo#281294 Forward-Port-Of: odoo/odoo#280927
Original PR description
On python 3.10.12 `test_export_translatable_resources` fails. This is fixed in this commit build-944659 I only tested it on 17.0 since we do not seem to have the build error on higher versions. But the minimum python version is 3.10 until [excluding saas-19.1](https://github.com/odoo/odoo/blob/11ee42b4bf70a1008b06d13a48263e42c381aeed/odoo/release.py#L39) Forward-Port-Of: odoo/odoo#281294 Forward-Port-Of: odoo/odoo#280927
32 changes
Enhancements to existing features
The recurring donation product now includes a default placeholder image in the website shop. This gives donation pages a more complete and consistent appearance when no custom product image is set.
Original PR description
Added placeholder image for the recurring donation product. task-6361612 Forward-Port-Of: odoo/enterprise#126209
The timesheet assistant now includes additional built-in rules based on beta tester feedback, making it more useful out of the box. The beta warning has also been removed, reflecting that the feature is now considered ready for regular use.
Original PR description
This commit's purpose is to add a few built in aw rules, as that was a demand from the odoo expert who beta tested the assistant. It also removes the 'beta' warning, as the feature is reaching a useable state. task-6385660
Spreadsheet list headers can now be translated, making dashboards easier to understand for users working in different languages. The change also ensures these header terms are detected for translation when spreadsheet data is processed.
Original PR description
This commit adds the support to translate list headers in the spreadsheet, as well as the term extraction from the json. Task: 6452895
Hong Kong payroll users can now attach multiple rental payment proofs through a clearer button-based flow instead of a single confusing field. The rental similarity check was also refined to avoid false matches, especially after migrations or for non-overlapping rentals from the same employee.
Original PR description
As the system now starts to be used by real users, we noticed a few points of improvement that can easily be done in stable and will provide a better UX when interacting with the system. The payment…
As the system now starts to be used by real users, we noticed a few points of improvement that can easily be done in stable and will provide a better UX when interacting with the system. The payment proof as a field was a consequence of multiple iterations of the system; but it ended up only as a way to input the proof and nothing else. It is confusing, only allows one proof at a time, and is overall not nice to use. To improve that, we will remove the field and replace it with an 'Attach Payment Proof' button similar to the expense app, allowing for a better experience. The similar rental check was checking even if all the related fields were empty. On a database migrating from a previous version, this leads to ALL the rentals to be marked as similar, which isn't ideal. The same check was also comparing multiple rentals from the same employee as long as they are active. As rentals for an employee cannot overlap, it makes no sense to check this case and cause false positives. task-6448054 Forward-Port-Of: odoo/enterprise#126764
German POS certification now handles retail and restaurant transaction synchronization separately, matching Fiskaly’s expected workflows. This improves compliance reliability by starting transactions earlier, reducing unnecessary updates for retail sales, and ensuring restaurant kitchen changes are synchronized accurately without duplicating already sent items.
Original PR description
In this commit: ------------------ - Maintain separate Fiskaly transaction flows for retail (short tx) and restaurant (long tx) orders as discussed with the Fiskaly team. - `Initialize order…
In this commit: ------------------ - Maintain separate Fiskaly transaction flows for retail (short tx) and restaurant (long tx) orders as discussed with the Fiskaly team. - `Initialize order transactions` with an empty payload when the `first product` is added. - Start `receipt transactions` with an empty payload when the `first payment line` is added. - For retail flows, no intermediate order updates are sent to Fiskaly before finalization. - For restaurant flows, create additional transaction updates during kitchen synchronization. Ensure already synchronized products are not resent, and only newly added or updated quantities are included in the payload. - `Finalize order and receipt transactions` with complete order lines and payment details when we validate the order. task: 6208963 Reference: <img width="1863" height="1285" alt="de_tss_flow" src="https://github.com/user-attachments/assets/9140788e-7948-4a08-9f11-27197b22ca8b" /> Forward-Port-Of: odoo/enterprise#120529 Forward-Port-Of: odoo/enterprise#117526
Resolved issues and error corrections
Attachments added to employee records and leave requests now create documents in the appropriate employee folder instead of the general Employees root folder. Sick leave attachments also now correctly generate related documents, making HR document organization more reliable.
Original PR description
Before this commit, when adding an attachment to a leave or a employee version the mixin was configured to create the document in the root folder of Employees which was not very convenient. In addition, when creating a Sick leave with an attachment, no document was ever created. This commit fix both those bugs. Task-6095811 Forward-Port-Of: odoo/enterprise#126199 Forward-Port-Of: odoo/enterprise#112993
Click & collect rental orders now check availability against the warehouse the customer selected. This prevents rentals in one location from incorrectly blocking stock in another location, reducing failed add-to-cart attempts for customers.
Original PR description
When using the click & collect option, the available qty for renting was not taking the selected warehouse into account. Steps to reproduce: ------------------- * Create 2 different warehouses with 2…
When using the click & collect option, the available qty for renting was not taking the selected warehouse into account. Steps to reproduce: ------------------- * Create 2 different warehouses with 2 different adresses * Create a product available for renting * Setup the product to use serial numbers * Create 2 serial number, 1 in each warehouse * Activate the click & collect option on the website * Create a first sale order to collect in warehouse 1 * In the backend, confirm the order and pick it up * Go back to the website and make a second order for the second warehouse > Observation: When clicking on the "Add to cart" you get an error saying that there is no quantity available Why the fix: ------------ When computing the `product_rented_quantities` it would look for `sale.order.line` in all the warehouse. So it would find the line from the first order even if it's not linked to the selected warehouse. So we just add a new element to the domain to filter out the incorrect warehouses. opw-6328475 Forward-Port-Of: odoo/enterprise#126817 Forward-Port-Of: odoo/enterprise#124969
Fixed an issue that could crash forms when Approval Requests were linked through a Studio-created field and the form recalculated values. The change avoids sending notifications from temporary records, making approval-related form updates more reliable without changing normal user workflows.
Original PR description
**Before this change** We have the potential to attempt to send a notification email from virtual records created by our `BaseModel.new()` method. This can happen during an `onchange` request, given…
**Before this change** We have the potential to attempt to send a notification email from virtual records created by our `BaseModel.new()` method. This can happen during an `onchange` request, given that we'll be working with a virtual "snapshot" record to recompute potentially changed values for our origin record after a change to one or more values. This issue manifests when using Studio to attach a many2many field to a form view, where the related model is "Approval Request". If an approval request record in either the "Approved" or "Refused" state is attached to our record via this new Studio field, any `onchange` requests will trigger this bug. This is because we can't send messages on a virtual record. **After this change** Prevent the creation and sending of a message if we are computing the request status of a virtual `approval.request()` record. The field `request_status` on this model is computed and stored, but the fact that it is a computed field means that it must be recomputed for a virtual record, even if the origin record already has a stored `request_status`. Thus, we may need to compute a `request_status` value for an ephemeral "snapshot" record. Though the issue only manifests for the "Approved" and "Refused" states, this PR expands on a test that covers every approval request state. opw-6390453 Forward-Port-Of: odoo/enterprise#125374
Accrual list reports now remember the selected "As of" date when users open a report line and return using the breadcrumb. This prevents the report from unexpectedly switching back to today's date and helps accounting users continue their review with the intended cutoff date.
Original PR description
Issue: In accrual list reports (Billed Not Received / Invoiced Not Delivered), selecting an "As of" date, opening a line, and returning with the breadcrumb resets the date filter to the default value…
Issue: In accrual list reports (Billed Not Received / Invoiced Not Delivered), selecting an "As of" date, opening a line, and returning with the breadcrumb resets the date filter to the default value (today's date) Steps to reproduce: 1) Open an accrual list report ( Accounting > Audit > Purchases > Bill to receive / Billed Not Received OR Invoices to be issues / invoiced Not delivered) 2) Pick any "As of" date 3) Open any row 4) Click breadcrumb to return to the accrual list 5) Observe the "As of" date has been reset to today's date To generate some data you could: create a PO, then upload the bill, validate the receipt, then you'll find it in bills received Cause: `AccrualListController.setup()` always initialized state.date with a fresh default date and did not re-put the previously saved `accrual_entry_date` from restored context https://github.com/odoo/enterprise/blob/899f0d45b2ae1dc4e5e06a2e0acb3d006d12d563/account_reports/static/src/views/accrual_list_controller.js#L10-L16 Although `setDate()` stored the selected date in context, `setup()` overwrote the UI state on controller recreation https://github.com/odoo/enterprise/blob/899f0d45b2ae1dc4e5e06a2e0acb3d006d12d563/account_reports/static/src/views/accrual_list_controller.js#L61-L65 Solution: - Persist `accrual_entry_date` in `AccrualListSearchModel` via `exportState()` / `_importState()`, so the date is restored in search context before the list model loads on breadcrumb navigation. - Initialize the date picker through `setDate()` in `onWillStart()` instead of hardcoding `DateTime.now()` in `setup()`, so restoration and user changes share the same code path. - In `setDate()`, reset grouped list caches (`currentGroups` and `groups`) before `root.load()`, because those caches are not keyed on `accrual_entry_date` and would otherwise show stale vendor groups after a date change or breadcrumb restore. opw-6232263 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/enterprise#126688 Forward-Port-Of: odoo/enterprise#118669
This change prevents the Website Sale Subscription app from failing to install if the default monthly subscription plan was previously deleted. It skips linking optional donation pricing data to that missing plan, allowing setup to continue normally.
Original PR description
Currently, an error occurs when user tries to install `website_sale_subscription` after deleting the monthly subscription plan. Steps to replicate: - Install `sale_subscription`. - Open Subscription…
Currently, an error occurs when user tries to install `website_sale_subscription` after deleting the monthly subscription plan.
Steps to replicate:
- Install `sale_subscription`.
- Open Subscription > Configuration > Recurring Plans.
- Delete the plan named `monthly`.
- Install `website_sale_subscription`.
Error:
```
ValueError: External ID not found in the system: sale_subscription.subscription_plan_month
odoo.tools.convert.ParseError: while parsing /home/odoo/odoo19/enterprise/website_sale_subscription/data/donation_data.xml:16, somewhere inside
<record id="product_recurring_donation_pricing_monthly" model="product.pricelist.item">
<field name="plan_id" ref="sale_subscription.subscription_plan_month"/>
<field name="product_tmpl_id" ref="product_recurring_donation"/>
<field name="fixed_price">1.0</field>
<field name="pricelist_id" eval="False"/>
</record>
```
Cause:
- Error is raised when assigning the `Monthly` subscription plan in the `website_sale_subscription` master data because the user has deleted the `Monthly` subscription plan.
Solution:
- As the `plan_id` is not a required field, we can skip assigning the `plan_id` if it the record is not found.
sentry-7441124574
Forward-Port-Of: odoo/enterprise#125649Users can now revoke a Belgian CodaBox connection using either the fidu password or a valid IAP token. This fixes a mismatch between the server and client behavior, making account disconnection smoother when a token is available.
Original PR description
The user should be able to revoke the CodaBox connection by either entering the fidu password or by using a valid iap_token. This was implemented in the iap server but not in the client side, after this commit the user should be able to either revoke by using the fidu password or by using the iap_token. task-6348433 Forward-Port-Of: odoo/enterprise#126698
Payroll users reviewing a pay run now see a dedicated list of only the time off records that caused errors. This avoids confusion from reopening the same calendar-style screen and helps users quickly identify and fix the records blocking payroll processing.
Original PR description
## Steps to reproduce: - Create a pay run with an error in the Time Offs step. - Click Continue. - Click Review Time Offs. ## Issue: Review Time Offs reused the regular Time Offs Gantt action. Since the user was already on the time off screen, opening it could look like nothing happened. The Gantt view was also misleading because it displayed all time off records for employees having at least one problematic record, instead of showing only the records that required review. ## Fix: Open a dedicated Time Offs to Review list/form action on hr.leave. The action now uses a domain matching only the problematic time off records for the pay run, so users can review and act directly on the records causing the error. Task-6361141 Forward-Port-Of: odoo/enterprise#123459
The cohort report now calculates average retention based on the size of each cohort, rather than treating every cohort equally. This gives business users a more accurate view of overall retention when comparing groups of different sizes.
Original PR description
Steps to reproduce: - Open a retention cohort with cohorts of different sizes - Compare the average row with the overall retained population Issues: The average row gives every cohort the same weight. A cohort of one record at 0% retention and a cohort of nine records at 100% retention therefore displays 50% instead of 90%. Solution: Weight each cohort percentage by its initial cohort value. Forward-Port-Of: odoo/enterprise#126027
User-facing messages and warnings now show translated names for dropdown-style field values across several Odoo apps. This improves clarity for users working in languages other than English and makes reports, payroll, accounting, recruitment, IoT, POS, and localization messages more consistent.
Original PR description
The `selection` attribute of `fields.Selection` is not generally translated (unless it is a function instead of a list). For user facing strings, we generally need to translate the value displayed. Forward-Port-Of: odoo/enterprise#126957 Forward-Port-Of: odoo/enterprise#126538
Automatic bank reconciliation rules are now created and matched more accurately by considering transaction text and whether amounts are incoming or outgoing. Users will see more relevant reconciliation suggestions for the selected journal, reducing incorrect matches and manual cleanup.
Original PR description
Reconcile models automatically created now use contains instead of match regex and take the amount into consideration when creating the rule as well as checking for existing rules, it's checked whether all of the lines are positive or negative. Added an extra filter on the reconcile models so that it only shows rules that would be applied on the journal, and did some optimizations in the substring matching. task-6140372 Forward-Port-Of: odoo/enterprise#126927 Forward-Port-Of: odoo/enterprise#117256
This fix restores missing styling for spreadsheet side panels in the backend. Users should see the affected panels display correctly again after a previous CSS reorganization accidentally omitted the shared styling.
Original PR description
During the reorganisation of the css in #114180, the generic sidepanel.css file was removed from every assets. It belongs to the bundle assets at is impacts sidepanels that are only available in the backend (i.e. not in public spreadsheets) Task-6448906 Forward-Port-Of: odoo/enterprise#126850
Replacing a Sign document now keeps multiple signature fields correctly tied to the same signer. This prevents duplicate signer entries and helps document signing workflows remain accurate after a file is replaced.
Original PR description
### Description of the issue/feature this PR addresses: This PR fixes an issue in the Sign module where replacing a document breaks the link between a signer and their multiple signature fields,…
### Description of the issue/feature this PR addresses: This PR fixes an issue in the Sign module where replacing a document breaks the link between a signer and their multiple signature fields, causing Odoo to erroneously generate separate signers for each individual field. ### Current behavior before PR: When a document with multiple signature fields assigned to the same person is replaced, the _copy_sign_items_to function duplicates the sign.item records. During this duplication process, Odoo duplicates the old responsible_ids, creating copies with new ids. These new copies overwrite the old responsible_ids, ensuring that the newly created sign_items have entirely new responsible_ids. Because a shared responsible_id is the primary key Odoo uses to group multiple signature items under a single signer, this change in ID causes the system to lose the grouping. As a result, Odoo treats each copied field as belonging to a completely new, separate signer. _Note_: Because of the limitation mentioned before, any responsible_id that is passed through the copy function, and thereby the copy_data function, is overwritten with new ids. The only work-around then is to update the responsible_id value attached to the new_sign_item after the copy_data function has completed and the new_sign_item has been created. ### Desired behavior after PR is merged: The original responsible_id is explicitly carried over and assigned to the newly copied sign.item immediately after the copy operation completes. This ensures the copied signature fields retain their original role IDs and grouping, keeping them correctly assigned to the single original signer. opw-6354334 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/enterprise#123628
Changing a payslip to a pay structure that does not use worked day lines now clears outdated day entries correctly. Belgian payroll reporting was also adjusted so off-cycle payments without worked day lines are still counted in DMFA remuneration reporting.
Original PR description
hr_payroll: Previously, changing to a structure with `use_worked_day_lines = False` (e.g., 13th month) caused `valid_slips` to be empty and return early, leaving stale worked day lines on the payslip. This commit resets the worked_days_lines before filtering for valid payslips. l10n_be_hr_payroll: After fixing the payroll bug and clearing worked_days_lines correctly, the DMFA report fails to correctly consider remunerations since the off-cycle payslips do not have worked_days_lines anymore. This commit backports a fix from odoo/enterprise#106689 to not skip remunerations for payslips with no worked days lines. task-6401942 Forward-Port-Of: odoo/enterprise#124986
Fixed an issue that could cause event badge printing to fail when a badge template included an image. This helps event staff print attendee badges reliably without interruptions.
Original PR description
Before this commit, some faulty logic in the `load_image` function caused a traceback when the ESC/LABEL badge template tried to use an image field. This bug only surfaced recently due to changes in how binary fields are accessed. After this commit, the logic is fixed and the traceback no longer occurs. task-6452486 Forward-Port-Of: odoo/enterprise#127017
The Sign portal now counts only documents that still need action from the signed-in user. This prevents completed signature requests from continuing to appear in the user’s to-sign total, making the portal status clearer and more accurate.
Original PR description
Version: 18.0 Steps to reproduce: - Create a sign request with two signers. - Assign the first signature to a portal user. - Log in as the portal user and sign the document. Issue: After signing, the to-sign count in the portal does not decrease. This is because the query only checks the overall sign request state instead of the individual signer's item state, so the count remains unchanged Fix: Added an item level state check to the count query so it only counts items that are still pending for that specific user. Task ID: 6412976 Forward-Port-Of: odoo/enterprise#126962 Forward-Port-Of: odoo/enterprise#125632
Google Reserve availability responses now avoid reporting more open spots than the total available spots. This prevents rare configuration mistakes from sending confusing or invalid availability information to Google.
Original PR description
This commit makes sure that we never send more "spots_open" than there are "spots_total" when Google Reserve asks for availabilities. This could happen in very rare case when customers create configurations that do not make sense (for example a table of 6 but no management of capacities and configuring 125 spots per resource). Task-6449615 Forward-Port-Of: odoo/enterprise#126855
This fixes a missing internal helper that could cause bulk product imports to fail when subscription billing settings were updated. Businesses can now import or update subscription products more reliably without encountering an unexpected error.
Original PR description
The port https://github.com/odoo/enterprise/commit/68640b5bddf51a8cbf58d3af3628cd4b57e08913 added a call to self._get_confirmed_order_lines() in product.template.write() (on import, when recurring_invoice changes), but the helper itself was never ported to 19.0. Importing products in bulk then fails with AttributeError: 'product.template' object has no attribute '_get_confirmed_order_lines'. Restores the method from master (PR https://github.com/odoo/enterprise/pull/117046) at the end of the ProductTemplate class. Forward-Port-Of: odoo/enterprise#122745 Forward-Port-Of: odoo/enterprise#122146
Fixed an issue where appointment types with non-ASCII names, such as Arabic titles, could get stuck in an endless redirect when a customer selected a time slot. Customers can now continue to the booking information form normally, improving access for multilingual appointment pages.
Original PR description
Clicking a slot on an appointment type with a non-ASCII name (for example an Arabic title) puts the browser in an endless 301 loop, so the info form never opens. ### Steps to reproduce - Create an…
Clicking a slot on an appointment type with a non-ASCII name (for example an Arabic title) puts the browser in an endless 301 loop, so the info form never opens. ### Steps to reproduce - Create an appointment type with an Arabic name, e.g. `عنوان`. - Open its page and pick a time slot. - The browser keeps redirecting on `/appointment/<slug>/info` and fails with "too many redirections". ### Cause The info URL is built from the slug `<name>-<id>`, here `عنوان-1`. We build a `URL` with `encodeURIComponent(slug)`, so `url.href` is already encoded once (`عنوان` becomes `%D8%B9...`). But we then navigate with `encodeURI(url.href)`, and `encodeURI` escapes the `%` signs a second time, so `%D8%B9...` becomes `%25D8%25B9...`. The slug is now encoded twice. To canonicalize the URL, the server decodes the request path and the path it rebuilds from the route, once each, and redirects if they differ. For a normal URL they are equal. For ours they are not, because one side is decoded one step less than the other, so the server keeps answering 301 with the same double-encoded URL. An ASCII slug has no `%` for `encodeURI` to escape, so only non-ASCII names hit this. ### Fix Navigate to `url.href` directly. It is already encoded, so the extra `encodeURI` only broke it. Same fix on the manual resource confirmation path. opw-6409641 Forward-Port-Of: odoo/enterprise#126852 Forward-Port-Of: odoo/enterprise#125497
Payslip reports now correctly hide note sections that contain only empty formatting rather than real content. This prevents blank note areas from appearing on payroll documents, keeping reports cleaner and more professional.
Original PR description
The condition was only checking if the note field was truthy. Actually, this can be a problem if the field is with only empty tags. Instead, we should use is_html_empty. Forward-Port-Of: odoo/enterprise#127052 Forward-Port-Of: odoo/enterprise#127008
Dutch SBR tax return exports now use the Tax Unit VAT number when a tax unit is selected, instead of incorrectly using the company’s Omzetbelastingnummer. This prevents tax authority rejections for fiscal unity filings while keeping the company-level number for single-company returns.
Original PR description
**Steps to reproduce:** * Install the **Netherlands - SBR** (`l10n_nl_reports_sbr`) and **Netherlands - SBR OB Nummer** (`l10n_nl_reports_sbr_ob_nummer`) modules. * Create two companies with Dutch…
**Steps to reproduce:** * Install the **Netherlands - SBR** (`l10n_nl_reports_sbr`) and **Netherlands - SBR OB Nummer** (`l10n_nl_reports_sbr_ob_nummer`) modules. * Create two companies with Dutch localization. * Go to **Accounting → Configuration → Tax Units** and create a Tax Unit with its own **Tax ID** (e.g. `NL826317558B01`), adding both companies. * On the main company form, fill in the **Omzetbelastingnummer** field (e.g. `123456782B90`). * Go to **Accounting → Reporting → Tax Return**, select the Tax Unit in the filter, and click **XBRL → Download XBRL File**. **Observed behavior:** * The `<xbrli:identifier>` in the exported XBRL file contains the company's **Omzetbelastingnummer** (`123456782B90`) instead of the Tax Unit's VAT (`826317558B01`). * The tax authority rejects the return because the identifier does not match the fiscal unity registration. **Cause:** * `_get_sbr_identifier()` in `l10n_nl_reports_sbr_ob_nummer` unconditionally returns `self.env.company.l10n_nl_reports_sbr_ob_nummer` before consulting the Tax Unit. * The `super()` call, which correctly routes to `tax_unit.vat` via `report.get_vat_for_export()`, is only reached when the company field is empty — so the Tax Unit's VAT is never used when a company OB-number is set. **Fix:** * When a Tax Unit is active in the report options, delegate immediately to `super()._get_sbr_identifier()`, which resolves `tax_unit.vat` through the existing `get_vat_for_export()` logic. * The company-level `l10n_nl_reports_sbr_ob_nummer` override is preserved as a fallback for the `company_only` (no Tax Unit) case. opw-6350840 Forward-Port-Of: odoo/enterprise#126999 Forward-Port-Of: odoo/enterprise#125167
This fixes payroll worked-day calculations so they can correctly consider inactive related records when generating payslips. It helps avoid incorrect payroll results in edge cases where archived records still affect employee pay history or contract data.
Original PR description
Forward-Port-Of: odoo/enterprise#114877
Fixed an issue in the Barcode app where selecting products from mixed packaged and unpackaged delivery lines could leave two lines selected at once. This makes warehouse picking clearer and helps prevent operator confusion during deliveries that include both package types.
Original PR description
**Steps to reproduce:** - Enable "Move Entire Packages" setting on deliveries - Make a product A, that has a package P1, on hand qty of 1 - Make product B that don't have a package, but on hand qty…
**Steps to reproduce:** - Enable "Move Entire Packages" setting on deliveries - Make a product A, that has a package P1, on hand qty of 1 - Make product B that don't have a package, but on hand qty of 1 - Make a delivery that has both of those products, requested qty of 1 for both - Mark it as todo - Go to the barcode app, select the delivery - Select the line with product B - Select the line with product A --> The line with product B is not unselected **Why the fix:** When we have a mix of packaged products and products without a package on the same operation, they are handled separately. The products without a package are handled in https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L388-L392 that calls https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L1277-L1284 But as you can see, there are no mention of the selected package line, which is stored in **this.lastScanned.packageId**. As we do not touch this variable, the selected package line stays selected. The same is true for the other way around, when we select a package line we call https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L394-L398 This function does not care for the **selectedLineVirtualId** which represents the selected line without a package. To avoid this and make it so that only one line is selected even if they have different package, we now set the corresponding value to false to unselect the other line in all situation. This is basically how it's done in https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L1202-L1208 to unselect every line regardless of packages. opw-6266203 Forward-Port-Of: odoo/enterprise#126790 Forward-Port-Of: odoo/enterprise#122038
Template-created items such as Double Opt-in contact lists and server actions are now preserved when Marketing Automation is upgraded. This prevents campaign setup data from unexpectedly disappearing after an app upgrade, reducing disruption for marketing teams.
Original PR description
When a user chooses the "Double Opt-in" template (or others using `_create_records_with_xml_ids`), the system creates records like the "Confirmed contacts" list and a server action. It also adds an…
When a user chooses the "Double Opt-in" template (or others using `_create_records_with_xml_ids`), the system creates records like the "Confirmed contacts" list and a server action. It also adds an `ir.model.data` entry for them under the module, but sets `noupdate=False`. The problem is that during a module upgrade, Odoo's cleanup process (`_process_end`) deletes any record marked `noupdate=False` if it wasn't "reloaded" from a file. Since these records are created manually in the code and aren't in any XML file, they never get reloaded, so Odoo just deletes them and the records they point to. By setting `noupdate=True` when these rows are created, we tell the system to leave them alone during upgrades. Since these only exist at runtime and don't have a data file, we don't need to worry about them being updated later anyway. The helper was added in https://github.com/odoo/enterprise/commit/fd98660e352512e0b74d91958707687978154833. Steps to reproduce: 1. Install Marketing Automation 2. Go to Campaigns > New and pick the "Double Opt-in" template, then save 3. Confirm the "Confirmed contacts" mailing list and server action exist 4. Go to Apps and Upgrade Marketing Automation 5. Try to find the mailing list and server action again => They disappear after the upgrade. Ticket [link](https://www.odoo.com/odoo/project.task/6140191) opw-6140191 Forward-Port-Of: odoo/enterprise#115444
Spanish VAT record book exports now include taxable accounting entries created outside regular invoices, such as Point of Sale session closures and manual liquidations. This helps ensure VAT reporting is complete and aligned with tax obligations.
Original PR description
Currently, the Spanish VAT record books (Libros Registro de IVA) only include move types associated with invoices and bills. However, miscellaneous entries (type 'entry'), such as those generated by the Point of Sale session closures or manual liquidations, also carry tax obligations and must be reflected in these reports. Steps to reproduce: - Open a POS Session - Create an order, pay and close session - Go to Accouting > Reporting > Tax report - Select Generic Tax report - Print "VAT record Books" Issue: Only invoices and bills are visible in the excel file, and not the entry generated from point of sale. However, movements that are not related to invoices should be included in the VAT books. opw-5862529 Forward-Port-Of: odoo/enterprise#125768 Forward-Port-Of: odoo/enterprise#113681
Opening bank reconciliation directly from a bookmark or shared link now keeps the same behavior as opening it from the accounting dashboard. Automatic matching runs as expected, and upload options stay hidden for journals that use online synchronization, reducing manual work and avoiding confusing choices.
Original PR description
### Issue: When accessing the Bank Reconciliation view directly via URL or bookmark, auto-matching with reconciliation models may not trigger and the upload button may be visible on synchronized…
### Issue: When accessing the Bank Reconciliation view directly via URL or bookmark, auto-matching with reconciliation models may not trigger and the upload button may be visible on synchronized journals ### Cause: `_action_open_bank_reconciliation_widget` injects two context keys: - `auto_statement_processing`: triggers auto-reconciliation on statement creation - `bank_statements_source`: hides the upload button for synchronized journals When the view is accessed directly, these keys are not present, causing the UI to ignore them `auto_statement_processing` is now set directly in the user context via `onWillRender`/`onWillDestroy` in `BankRecKanbanController` `bank_statements_source` requires an ORM call to fetch the journal's value and is resolved via `fetchBankStatementsSourceInto` on startup Notes: The fix for `bank_statements_source` was added opportunistically while addressing `auto_statement_processing` Steps to reproduce: - Install `accountant` with demo data - Duplicate the Bank Journal and set Bank Feeds to Online Synchronization - Open the Accounting Dashboard and open the Bank (copy) - Create a transaction (Label: Test, any amount) and click Add & Close - In the 3 dots menu, choose Manage Models - Create a Reconciliation Model (Label contains: Test, Lines: any account, default values) - Click Automate - Go back to the Bank Reconciliation page and verify: -- The transaction is reconciled automatically -- No Upload button is displayed - Create a new transaction, it should be reconciled automatically - Copy the URL and open it in a new tab - Create a new transaction Before the fix, the transaction is not reconciled and the Upload button is present opw-6391107 Forward-Port-Of: odoo/enterprise#127020 Forward-Port-Of: odoo/enterprise#126359
Code cleanup and technical improvements
The live chat customer information panel now handles the Open Tickets section more consistently by removing a redundant check. This reduces the risk of display issues or crashes and adds test coverage to keep the behavior stable.
Original PR description
Enterprise counterpart of "[FIX] crm_livechat, *: prevent crash in the info panel", which explains why the condition of the caller goes away. This commit drops the same condition on the "Open tickets" block, and covers that block with a test. https://github.com/odoo/odoo/pull/280430 Forward-Port-Of: odoo/enterprise#126761 Forward-Port-Of: odoo/enterprise#126715
This update removes an outdated compatibility layer in several Odoo Enterprise screens now that the newer interface reference system is fully in place. It should not change day-to-day behavior for users, but it simplifies the code and reduces the risk of future maintenance issues.
Original PR description
Removes the leftover t-custom-ref migration shims Community: https://github.com/odoo/odoo/pull/280967
5 changes
Resolved issues and error corrections
This fix prevents users in multi-company manufacturing setups from hitting an unavoidable error when creating operation quality checks. It ensures quality team company handling works correctly even when the full quality control module is not installed.
Original PR description
This commit actually reverts [1] and manually forwards [2]. Suppose `mrp_workorder` installed and `quality_control` uninstalled. Because of the default value provided by [1], the only existing quality team is linked to the first company. As a result, when using another company, if the user tries to create an operation step (i.e., a QCP), it will raise an error when the onchange tries to load the default team in charge: https://github.com/odoo/enterprise/blob/f9c99f937bd64e5a0acb4bc88b1fc08249250c4e/quality/models/quality.py#L141-L142 However, the `quality` module doesn't provide any view to create such a team. tldr The module raises an error that is actually impossible to solve... Let's avoid it in the above situation. [1] https://github.com/odoo/enterprise/commit/f9c99f937bd64e5a0acb4bc88b1fc08249250c4e [2] https://github.com/odoo/enterprise/commit/8cd5c9322bef7db49a90d4aef844dd0ba267058e Forward-Port-Of: odoo/enterprise#126364
This fix ensures a Swiss payroll value is properly recorded during ELM transmission processing. It helps payroll teams keep more complete and accurate transmission logs for compliance and troubleshooting.
Original PR description
Forward-Port-Of: odoo/enterprise#127241
This fix ensures Belgian payroll reports the correct mobility budget amount when a remaining balance is paid after the employee's current payroll version no longer includes a mobility budget. It uses the previous quarter's information instead of reporting zero, helping keep DMFA declarations accurate.
Original PR description
When the mobility budget balance is paid on a version that no longer carries a mobility budget, fall back to the previous quarter's version to declare the correct amount instead of 0. Task-6384786
Helpdesk tickets no longer appear to have met their SLA as soon as a future deadline is assigned. The SLA reached status now turns on only when the ticket actually reaches the target stage, while late completion remains tracked separately.
Original PR description
### Steps to Reproduce: 1. Go to Helpdesk and create an SLA 2. Create a new Ticket 3. Use Studio to add the field `sla_reached` 4. Apply the SLA 5. Notice that the field is True ### Description of…
### Steps to Reproduce: 1. Go to Helpdesk and create an SLA 2. Create a new Ticket 3. Use Studio to add the field `sla_reached` 4. Apply the SLA 5. Notice that the field is True ### Description of the issue/feature this PR addresses: **Issue:** The `_compute_sla_reached` method in on `helpdesk_ticket.py` determines whether an SLA has been reached by checking if `exceeded_hours` is less than 0 on its `helpdesk.sla.status` records. Since every newly assigned SLA has a future deadline, `exceeded_hours` starts as negative (AKA <0), so the ticket is immediately flagged as `sla_reached = True` before any progress has been made. Conversely, a ticket that reaches its target stage after the deadline has `exceeded_hours >= 0`, so it's incorrectly flagged as `sla_reached = False` even though the SLA target was genuinely reached (it was just late). **Solution:** Change the domain in `_compute_sla_reached` to check `reached_datetime != False` instead of `exceeded_hours < 0`, matching the field already listed in the method's `@api.depends` and the same field `_sla_reach()` sets when a ticket enters its target stage. This makes `sla_reached` reflect actual stage progression rather than a time-remaining calculation. ### Current behavior before PR: A newly created ticket with a pending SLA shows `sla_reached = True` and `sla_success = True` immediately upon creation, before the ticket has moved to any target stage. SImilarly, a ticket that reaches its target stage after the SLA deadline is incorrectly marked `sla_reached = False`. ### Desired behavior after PR: `sla_reached` is False on ticket creation and only becomes True once the ticket actually enters the SLA's target stage. Lateness continues to be tracked separately and correctly via `sla_reached_late` opw-6361851 Forward-Port-Of: odoo/enterprise#126432
The live currency rate update now uses the new Romanian National Bank subdomain for exchange rate files. This keeps automated exchange rate updates working after the bank retires the old web address in August 2026.
Original PR description
As of 6 August 2026, the XML files used by software applications to retrieve daily exchange rates will no longer be available directly through addresses on the www.bnr.ro domain and will be accessible exclusively via the curs.bnr.ro subdomain. The XML file names will remain unchanged; only the access domain will be modified. no-task Forward-Port-Of: odoo/enterprise#127177
6 changes
Enhancements to existing features
Budget report loading has been optimized by changing how budget lines are matched to related accounting data. This reduces very slow report loads on larger databases, improving usability for teams working with many budget and analytic records.
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-6345552Resolved issues and error corrections
This fix ensures Belgian payroll reports the correct mobility budget balance when it is paid after the related contract no longer has an active mobility budget. It uses the previous quarter's contract information so declarations avoid incorrectly showing a zero amount.
Original PR description
When the mobility budget balance is paid on a contract that no longer carries a mobility budget, fall back to the previous quarter's contract to declare the correct amount instead of 0. Task-6384786
Steps to reproduce: - Create a sale order with a down payment term. - Invoice the down payment (down payment invoice A). - Credit that down payment invoice directly (credit note A), without reconciling it with anything else. - Generate the FatturaPA XML for credit note A. - Observe that DatiFattureCollegate lists both down payment invoice A and credit note A itself, instead of only down payment invoice A. On an order with several down payment invoices/credit notes over time, every one of th
Original PR description
Steps to reproduce: - Create a sale order with a down payment term. - Invoice the down payment (down payment invoice A). - Credit that down payment invoice directly (credit note A), without…
Steps to reproduce: - Create a sale order with a down payment term. - Invoice the down payment (down payment invoice A). - Credit that down payment invoice directly (credit note A), without reconciling it with anything else. - Generate the FatturaPA XML for credit note A. - Observe that DatiFattureCollegate lists both down payment invoice A and credit note A itself, instead of only down payment invoice A. On an order with several down payment invoices/credit notes over time, every one of them is listed instead of just the document the current credit note actually reverses. Cause of the issue: _l10n_it_edi_export_data built downpayment_moves from self.invoice_line_ids._get_downpayment_lines().move_id with no filtering. _get_downpayment_lines() (sale override) returns every invoice line ever created against the same down payment sale order line, across the whole life of the order, not just the invoice the current document actually relates to. The template renders DatiFattureCollegate for every one of those moves unconditionally, on top of the already-correct reversed_entry_id/reconciled_moves fallback, including the current document itself. Solution: Restrict downpayment_moves to lines with a negative price_subtotal, mirroring the existing down payment deduction-line detection a few lines above, and explicitly exclude the current document. This limits DatiFattureCollegate's down payment entries to the case they are meant for: a final invoice actually deducting a previously invoiced down payment. opw-6429716
**Steps to Reproduce:** 1. Send a message to Marc demo with Mitchell admin or vice-versa, read the message from reciever's side. 2. Click on seen-by indicator from sender's side, make sure the dialog appears and then Press `'ESC'`. 3. Chat window closes whereas the dialog should have closed. Since #169737, pressing 'esc' on the seen-by dialog closes the chat window instead of the dialog. The chat window's root element has a keydown handler that closes the window on `'escape'`, and cat
Original PR description
**Steps to Reproduce:** 1. Send a message to Marc demo with Mitchell admin or vice-versa, read the message from reciever's side. 2. Click on seen-by indicator from sender's side, make sure the dialog…
**Steps to Reproduce:** 1. Send a message to Marc demo with Mitchell admin or vice-versa, read the message from reciever's side. 2. Click on seen-by indicator from sender's side, make sure the dialog appears and then Press `'ESC'`. 3. Chat window closes whereas the dialog should have closed. Since #169737, pressing 'esc' on the seen-by dialog closes the chat window instead of the dialog. The chat window's root element has a keydown handler that closes the window on `'escape'`, and catches focus by default whenever something non-focusable is clicked inside it (e.g. the seen-by indicator). The seen-by dialog's content had no focusable element, so it never grabbed focus for itself, leaving focus on the chat window. Pressing 'escape' therefore closed the chat window instead of the dialog. This commit fixes the issue by adding tabindex on the template, letting the dialog grab focus like other dialogs/popovers already do, so `'escape'` is handled by the dialog first. task-4895004
On python 3.10.12 `test_export_translatable_resources` fails. This is fixed in this commit build-944659 I only tested it on 17.0 since we do not seem to have the build error on higher versions. But the minimum python version is 3.10 until [excluding saas-19.1](https://github.com/odoo/odoo/blob/11ee42b4bf70a1008b06d13a48263e42c381aeed/odoo/release.py#L39) Forward-Port-Of: odoo/odoo#280927
Original PR description
On python 3.10.12 `test_export_translatable_resources` fails. This is fixed in this commit build-944659 I only tested it on 17.0 since we do not seem to have the build error on higher versions. But the minimum python version is 3.10 until [excluding saas-19.1](https://github.com/odoo/odoo/blob/11ee42b4bf70a1008b06d13a48263e42c381aeed/odoo/release.py#L39) Forward-Port-Of: odoo/odoo#280927
When several xmlids point to the same record, PostgreSQL's UPDATE ... FROM can match multiple source rows to one target and pick an arbitrary value. Aggregate translations per res_id in import order so the later entry wins Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277818
Original PR description
When several xmlids point to the same record, PostgreSQL's UPDATE ... FROM can match multiple source rows to one target and pick an arbitrary value. Aggregate translations per res_id in import order so the later entry wins Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277818