Daily updates from Odoo
Monday, June 22, 2026
376 changes
25 changes
Enhancements to existing features
This update simplifies cash basis accounting in the French localization module by automatically disabling payment reconciliation. This change ensures that cash basis accounts align with standard French accounting practices and reduces potential user confusion. It's a minor improvement focused on clarity and consistency.
Original PR description
Cash basis accounts now have payment reconciliation set as false by default task-6226984
This update allows users to group and filter POS orders based on their DIAN transmission status. Previously, the system couldn't easily identify rejected or failed syncs, making it difficult to monitor the health of daily DIAN transmissions. This change provides better visibility and control over POS order synchronization with DIAN authorities.
Original PR description
The DIAN transmission status (l10n_co_edi_pos_dian_state) is a non-stored computed field, so it could not be used to group, filter or sort the POS Orders list: users had no way to isolate rejected or failed orders, nor to get an overview of daily sync health. Provide a compute_sql for the field so the ORM can express it in SQL, making it groupable/searchable/sortable without storing it. This avoids a schema change while keeping the value derived from the most recent DIAN document. task-6273842
Resolved issues and error corrections
This update prevents users from changing the status of a check if they don't have the necessary permissions. Previously, users without access to the main company of a tax unit would receive an error. Now, the status change button is disabled, ensuring data integrity and preventing incorrect status updates.
Original PR description
Before this commit: Only main company of tax unit have write access on check, so when main company is not selected and user tries to change status of check, access error is thrown. After this commit: Disable check status button if user don't have write access on check. task-5951364 Forward-Port-Of: odoo/odoo#271331
This update resolves a layout issue where the 'Cancel' button in the product screen's modal would float. The change adjusts the button's sizing and grid layout to ensure it fits correctly on various screen sizes, particularly tablets, improving the user experience. This ensures a consistent and functional layout for all users.
Original PR description
This PR fixes the issue of the Cancel button floating on the last row when the buttons wrap and other overflowing issues. Before this PR, we were targetting the screen's orientation and max-height, which worked in general but still let a few layout issues through. On tablets the buttons are large and squarish for better touch usability (which has the double function of leaving plenty of space for translations), this makes fitting them within the modal container without overflowing a bit more complex. Instead, we target ranges of the aspect-ratio of the screen and adjust the buttons squarish aspect-ratio and the number of grid columns accordingly. By controlling the grid's columns we're able to tell the last button (the Cancel button) to stretch to full width when needed as well as having a more balanced layout in both landscape and portrait views. task-6235164 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update corrects a rejection issue with the 3519 VAT reimbursement form, which was being flagged by the French tax authority (DGFiP). The fix ensures the correct 'millesime' (form version year) is used when generating the VAT report, resolving compatibility problems and allowing the form to be accepted. This prevents delays in VAT reimbursement processing.
Original PR description
The 3519 reimbursement form is rejected by the DGFiP with "Le millesime 25 du formulaire 3519 est inconnu dans la teleprocedure TVA". The 3310CA3 return is still accepted, because its layout is unchanged year-on-year, which hides the problem, but it is sent with a millesime that no longer matches the campaign. The millesime is the form-version year. The EDI-TVA 2026 campaign opened on 2026-02-09. last update: https://github.com/odoo/enterprise/pull/92542 opw-6275695 Forward-Port-Of: odoo/enterprise#120759
This update resolves an issue where users were unable to simultaneously edit the names of multiple projects. The fix prevents a technical error that occurred when multiple project records were updated at once. Additionally, the code was updated to ensure analytic account names are correctly updated during multi-editing.
Original PR description
Currently, an error will occur when user multi edits name of projects. Steps to replicate: - Install `project` and open projects. - From the list view select multiple projects and edit their name.…
Currently, an error will occur when user multi edits name of projects.
Steps to replicate:
- Install `project` and open projects.
- From the list view select multiple projects and edit their name.
Error:
```
File '/home/odoo/src/odoo/saas-19.3/addons/project/models/project_project.py', line 754, in write
analytic_account_to_update.write({'name': self.name})
File '/home/odoo/src/odoo/saas-19.3/odoo/orm/fields.py', line 1728, in __get__
record.ensure_one()
File '/home/odoo/src/odoo/saas-19.3/odoo/orm/models.py', line 5341, in ensure_one
raise ValueError('Expected singleton: %s' % self)
ValueError: Expected singleton: project.project(8, 9, 10)
```
Cause:
- As multiple records were changed at the moment, `self` had multiple recordsets and trying to access `self.name` [1] causes this error.
Solution:
- Avoided accessing `self.name` on a multi-recordset during multi-edit.
- Updated analytic account names using the name recieved in the vals.
For test_orm changes:
- Added these fields to the translated field write whitelist to explicitly mark this usage as supported as both the fields are translated.
- Copied `field_names` so that removing values during the test does not mutate the original whitelist.
[1]: https://github.com/odoo/odoo/blob/a69ec43f490735f639292d116b0207182c5b2581/addons/project/models/project_project.py#L608
sentry-7452096418
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#269830
Forward-Port-Of: odoo/odoo#267620This update ensures that when users simultaneously rename multiple projects from the list view, the linked folder names are automatically updated as well. Previously, the system didn't correctly reflect these changes, leading to inconsistencies. This fix improves data accuracy and simplifies project management workflows.
Original PR description
Currently, when user multi-edits projects names from list view the linked folder name doesnt get updated. Steps to replicate: - Install `documents_project` and open projects. - Select multiple projects and edit their names. Issue: - The project names get updated but their respective linked folder's name doesnt get updated. Cause: - During multi-edit, `self.documents_folder_id` contains the folders of all selected projects. - As a result, `len(self.documents_folder_id.project_ids) == 1` [1] is evaluated on the combined recordset instead of per project, causing the condition to fail whenever multiple projects are renamed. Solution: - Avoided accessing `self.name` on a `multi-recordset` during multi-edit. - Filtered projects individually and updated their document folders using the name in vals. [1]: https://github.com/odoo/enterprise/blob/3c2985ca6011700c271ed14e40e08c89be822753/documents_project/models/project_project.py#L101 sentry-7452096418
This update significantly speeds up how Odoo retrieves document access permissions, particularly for large databases like odoo.com. By switching to a subquery, the system now utilizes an index more efficiently, resulting in a much faster response time. This improves overall performance and user experience.
Original PR description
The '/my/counters' route is hit a lot of times on big databases like odoo.com One thing it does is a `self.env['documents.document].search_count([])` With this commit, we use a subquery for the…
The '/my/counters' route is hit a lot of times on big databases like odoo.com
One thing it does is a `self.env['documents.document].search_count([])`
With this commit, we use a subquery for the folder access instead of the current LEFT JOIN.
This ok since the number of folders is typically small compared to regular documents and the query is fast since it can use the index on 'type'
Before as portal user
------
2x Seq Scan
```
Aggregate (cost=1900290.73..1900290.74 rows=1 width=8) (actual time=282.271..282.276 rows=1 loops=1)
Buffers: shared hit=66629
-> Hash Left Join (cost=41649.94..1900044.55 rows=98472 width=0) (actual time=184.202..282.267 rows=3 loops=1)
Hash Cond: (documents_document.folder_id = documents_document__folder_id.id)
Filter: ((hashed SubPlan 2) OR ((documents_document.owner_id = 6) AND ((documents_document.shortcut_document_id IS NULL) OR (documents_document.shortcut_document_owner_id = 6))) OR (((documents_document.access_via_link)::text = ANY ('{edit,view}'::text[])) AND (documents_document.folder_id IS NOT NULL) AND ((hashed SubPlan 4) OR ((documents_document__folder_id.owner_id = 6) AND ((documents_document__folder_id.shortcut_document_id IS NULL) OR (documents_document__folder_id.shortcut_document_owner_id = 6)))) AND (documents_document.is_access_via_link_hidden IS NOT TRUE)))
Rows Removed by Filter: 28085
Buffers: shared hit=66629
-> Seq Scan on documents_document (cost=0.00..1857903.54 rows=187073 width=26) (actual time=0.022..109.288 rows=28088 loops=1)
Filter: ((active IS TRUE) AND ((hashed SubPlan 2) OR ((owner_id = 6) AND ((shortcut_document_id IS NULL) OR (shortcut_document_owner_id = 6))) OR (((access_via_link)::text = ANY ('{edit,view}'::text[])) AND (folder_id IS NOT NULL) AND (is_access_via_link_hidden IS NOT TRUE))))
Rows Removed by Filter: 342576
Buffers: shared hit=33313
SubPlan 2
-> Nested Loop (cost=0.85..357.41 rows=99 width=4) (actual time=0.008..0.009 rows=0 loops=2)
Buffers: shared hit=6
-> Index Scan using documents_access__partner_id_index on documents_access (cost=0.43..105.55 rows=103 width=9) (actual time=0.008..0.008 rows=0 loops=2)
Index Cond: (partner_id = 7)
Filter: ((expiration_date IS NULL) OR (expiration_date >= '2026-06-18 10:16:38'::timestamp without time zone))
Buffers: shared hit=6
-> Index Scan using documents_document_pkey on documents_document documents_access__document_id (cost=0.42..2.44 rows=1 width=9) (never executed)
Index Cond: (id = documents_access.document_id)
Filter: (((access_via_link)::text <> 'none'::text) OR ((documents_access.role)::text = ANY ('{view,edit}'::text[])))
-> Hash (cost=37016.64..37016.64 rows=370664 width=16) (actual time=164.521..164.521 rows=370664 loops=1)
Buckets: 524288 Batches: 1 Memory Usage: 17824kB
Buffers: shared hit=33310
-> Seq Scan on documents_document documents_document__folder_id (cost=0.00..37016.64 rows=370664 width=16) (actual time=0.005..100.491 rows=370664 loops=1)
Buffers: shared hit=33310
SubPlan 4
-> Nested Loop (cost=0.85..357.41 rows=99 width=4) (actual time=0.003..0.003 rows=0 loops=1)
Buffers: shared hit=3
-> Index Scan using documents_access__partner_id_index on documents_access documents_access_1 (cost=0.43..105.55 rows=103 width=9) (actual time=0.002..0.003 rows=0 loops=1)
Index Cond: (partner_id = 7)
Filter: ((expiration_date IS NULL) OR (expiration_date >= '2026-06-18 10:16:38'::timestamp without time zone))
Buffers: shared hit=3
-> Index Scan using documents_document_pkey on documents_document documents_access__document_id_1 (cost=0.42..2.44 rows=1 width=9) (never executed)
Index Cond: (id = documents_access_1.document_id)
Filter: (((access_via_link)::text <> 'none'::text) OR ((documents_access_1.role)::text = ANY ('{view,edit}'::text[])))
Planning:
Buffers: shared hit=69
Planning Time: 1.708 ms
Execution Time: 282.344 ms
```
After as portal user
-----
Only 1x Seq Scan
```
Aggregate (cost=2004948.33..2004948.34 rows=1 width=8) (actual time=116.161..116.165 rows=1 loops=1)
Buffers: shared hit=37942
-> Seq Scan on documents_document (cost=145660.16..2004490.36 rows=183187 width=0) (actual time=24.635..116.155 rows=3 loops=1)
Filter: ((active IS TRUE) AND ((hashed SubPlan 2) OR ((owner_id = 6) AND ((shortcut_document_id IS NULL) OR (shortcut_document_owner_id = 6))) OR (((access_via_link)::text = ANY ('{edit,view}'::text[])) AND (hashed SubPlan 5) AND (is_access_via_link_hidden IS NOT TRUE))))
Rows Removed by Filter: 370661
Buffers: shared hit=37942
SubPlan 2
-> Nested Loop (cost=0.85..357.41 rows=99 width=4) (actual time=0.008..0.009 rows=0 loops=1)
Buffers: shared hit=3
-> Index Scan using documents_access__partner_id_index on documents_access (cost=0.43..105.55 rows=103 width=9) (actual time=0.008..0.008 rows=0 loops=1)
Index Cond: (partner_id = 7)
Filter: ((expiration_date IS NULL) OR (expiration_date >= '2026-06-18 10:15:10'::timestamp without time zone))
Buffers: shared hit=3
-> Index Scan using documents_document_pkey on documents_document documents_access__document_id (cost=0.42..2.44 rows=1 width=9) (never executed)
Index Cond: (id = documents_access.document_id)
Filter: (((access_via_link)::text <> 'none'::text) OR ((documents_access.role)::text = ANY ('{view,edit}'::text[])))
SubPlan 5
-> Index Scan using documents_document__type_index on documents_document documents_document_1 (cost=0.42..145625.73 rows=13772 width=4) (actual time=11.688..11.689 rows=0 loops=1)
Index Cond: ((type)::text = 'folder'::text)
Filter: ((hashed SubPlan 4) OR ((owner_id = 6) AND ((shortcut_document_id IS NULL) OR (shortcut_document_owner_id = 6))))
Rows Removed by Filter: 28198
Buffers: shared hit=4629
SubPlan 4
-> Nested Loop (cost=0.85..357.41 rows=99 width=4) (actual time=0.002..0.002 rows=0 loops=1)
Buffers: shared hit=3
-> Index Scan using documents_access__partner_id_index on documents_access documents_access_1 (cost=0.43..105.55 rows=103 width=9) (actual time=0.001..0.002 rows=0 loops=1)
Index Cond: (partner_id = 7)
Filter: ((expiration_date IS NULL) OR (expiration_date >= '2026-06-18 10:15:10'::timestamp without time zone))
Buffers: shared hit=3
-> Index Scan using documents_document_pkey on documents_document documents_access__document_id_1 (cost=0.42..2.44 rows=1 width=9) (never executed)
Index Cond: (id = documents_access_1.document_id)
Filter: (((access_via_link)::text <> 'none'::text) OR ((documents_access_1.role)::text = ANY ('{view,edit}'::text[])))
Planning:
Buffers: shared hit=56
Planning Time: 1.544 ms
Execution Time: 116.216 ms
```
Before as internal user
--------
```
Aggregate (cost=1902165.43..1902165.44 rows=1 width=8) (actual time=332.919..332.925 rows=1 loops=1)
Buffers: shared hit=69223 read=370
-> Hash Left Join (cost=41649.94..1901908.04 rows=102955 width=0) (actual time=176.179..332.325 rows=10040 loops=1)
Hash Cond: (documents_document.folder_id = documents_document__folder_id.id)
Filter: ((hashed SubPlan 2) OR ((documents_document.owner_id = 1054906) AND ((documents_document.shortcut_document_id IS NULL) OR (documents_document.shortcut_document_owner_id = 1054906))) OR (((documents_document.access_internal)::text = ANY ('{view,edit}'::text[])) AND ((documents_document.company_id = 1) OR (documents_document.company_id IS NULL))) OR (((documents_document.access_via_link)::text = ANY ('{view,edit}'::text[])) AND (documents_document.folder_id IS NOT NULL) AND ((hashed SubPlan 4) OR ((documents_document__folder_id.owner_id = 1054906) AND ((documents_document__folder_id.shortcut_document_id IS NULL) OR (documents_document__folder_id.shortcut_document_owner_id = 1054906))) OR (((documents_document__folder_id.access_internal)::text = ANY ('{view,edit}'::text[])) AND ((documents_document__folder_id.company_id = 1) OR (documents_document__folder_id.company_id IS NULL)))) AND (documents_document.is_access_via_link_hidden IS NOT TRUE)))
Rows Removed by Filter: 27228
Buffers: shared hit=69223 read=370
-> Seq Scan on documents_document (cost=0.00..1859756.86 rows=190950 width=35) (actual time=15.029..155.718 rows=37268 loops=1)
Filter: ((active IS TRUE) AND ((hashed SubPlan 2) OR ((owner_id = 1054906) AND ((shortcut_document_id IS NULL) OR (shortcut_document_owner_id = 1054906))) OR (((access_internal)::text = ANY ('{view,edit}'::text[])) AND ((company_id = 1) OR (company_id IS NULL))) OR (((access_via_link)::text = ANY ('{view,edit}'::text[])) AND (folder_id IS NOT NULL) AND (is_access_via_link_hidden IS NOT TRUE))))
Rows Removed by Filter: 333396
Buffers: shared hit=33931 read=370
SubPlan 2
-> Nested Loop (cost=0.85..357.41 rows=99 width=4) (actual time=0.155..7.920 rows=148 loops=2)
Buffers: shared hit=1612 read=370
-> Index Scan using documents_access__partner_id_index on documents_access (cost=0.43..105.55 rows=103 width=9) (actual time=0.110..3.448 rows=200 loops=2)
Index Cond: (partner_id = 1800102)
Filter: ((expiration_date IS NULL) OR (expiration_date >= '2026-06-18 12:17:29'::timestamp without time zone))
Buffers: shared hit=192 read=190
-> Index Scan using documents_document_pkey on documents_document documents_access__document_id (cost=0.42..2.44 rows=1 width=9) (actual time=0.022..0.022 rows=1 loops=400)
Index Cond: (id = documents_access.document_id)
Filter: (((access_via_link)::text <> 'none'::text) OR ((documents_access.role)::text = ANY ('{view,edit}'::text[])))
Rows Removed by Filter: 0
Buffers: shared hit=1420 read=180
-> Hash (cost=37016.64..37016.64 rows=370664 width=25) (actual time=157.822..157.823 rows=370664 loops=1)
Buckets: 524288 Batches: 1 Memory Usage: 21336kB
Buffers: shared hit=33310
-> Seq Scan on documents_document documents_document__folder_id (cost=0.00..37016.64 rows=370664 width=25) (actual time=0.005..96.730 rows=370664 loops=1)
Buffers: shared hit=33310
SubPlan 4
-> Nested Loop (cost=0.85..357.41 rows=99 width=4) (actual time=0.019..0.372 rows=148 loops=1)
Buffers: shared hit=991
-> Index Scan using documents_access__partner_id_index on documents_access documents_access_1 (cost=0.43..105.55 rows=103 width=9) (actual time=0.005..0.078 rows=200 loops=1)
Index Cond: (partner_id = 1800102)
Filter: ((expiration_date IS NULL) OR (expiration_date >= '2026-06-18 12:17:29'::timestamp without time zone))
Buffers: shared hit=191
-> Index Scan using documents_document_pkey on documents_document documents_access__document_id_1 (cost=0.42..2.44 rows=1 width=9) (actual time=0.001..0.001 rows=1 loops=200)
Index Cond: (id = documents_access_1.document_id)
Filter: (((access_via_link)::text <> 'none'::text) OR ((documents_access_1.role)::text = ANY ('{view,edit}'::text[])))
Rows Removed by Filter: 0
Buffers: shared hit=800
Planning:
Buffers: shared hit=69 read=8
Planning Time: 2.116 ms
Execution Time: 333.013 ms
```
After as internal user
--------
```
Aggregate (cost=2006950.17..2006950.18 rows=1 width=8) (actual time=157.117..157.121 rows=1 loops=1)
Buffers: shared hit=39918
-> Seq Scan on documents_document (cost=145798.74..2006482.26 rows=187165 width=0) (actual time=16.595..156.590 rows=10040 loops=1)
Filter: ((active IS TRUE) AND ((hashed SubPlan 2) OR ((owner_id = 1054906) AND ((shortcut_document_id IS NULL) OR (shortcut_document_owner_id = 1054906))) OR (((access_internal)::text = ANY ('{view,edit}'::text[])) AND ((company_id = 1) OR (company_id IS NULL))) OR (((access_via_link)::text = ANY ('{view,edit}'::text[])) AND (hashed SubPlan 5) AND (is_access_via_link_hidden IS NOT TRUE))))
Rows Removed by Filter: 360624
Buffers: shared hit=39918
SubPlan 2
-> Nested Loop (cost=0.85..357.41 rows=99 width=4) (actual time=0.019..1.016 rows=148 loops=1)
Buffers: shared hit=991
-> Index Scan using documents_access__partner_id_index on documents_access (cost=0.43..105.55 rows=103 width=9) (actual time=0.012..0.262 rows=200 loops=1)
Index Cond: (partner_id = 1800102)
Filter: ((expiration_date IS NULL) OR (expiration_date >= '2026-06-18 12:16:29'::timestamp without time zone))
Buffers: shared hit=191
-> Index Scan using documents_document_pkey on documents_document documents_access__document_id (cost=0.42..2.44 rows=1 width=9) (actual time=0.004..0.004 rows=1 loops=200)
Index Cond: (id = documents_access.document_id)
Filter: (((access_via_link)::text <> 'none'::text) OR ((documents_access.role)::text = ANY ('{view,edit}'::text[])))
Rows Removed by Filter: 0
Buffers: shared hit=800
SubPlan 5
-> Index Scan using documents_document__type_index on documents_document documents_document_1 (cost=0.42..145763.43 rows=14124 width=4) (actual time=0.429..14.916 rows=4625 loops=1)
Index Cond: ((type)::text = 'folder'::text)
Filter: ((hashed SubPlan 4) OR ((owner_id = 1054906) AND ((shortcut_document_id IS NULL) OR (shortcut_document_owner_id = 1054906))) OR (((access_internal)::text = ANY ('{view,edit}'::text[])) AND ((company_id = 1) OR (company_id IS NULL))))
Rows Removed by Filter: 23573
Buffers: shared hit=5617
SubPlan 4
-> Nested Loop (cost=0.85..357.41 rows=99 width=4) (actual time=0.007..0.390 rows=148 loops=1)
Buffers: shared hit=991
-> Index Scan using documents_access__partner_id_index on documents_access documents_access_1 (cost=0.43..105.55 rows=103 width=9) (actual time=0.003..0.074 rows=200 loops=1)
Index Cond: (partner_id = 1800102)
Filter: ((expiration_date IS NULL) OR (expiration_date >= '2026-06-18 12:16:29'::timestamp without time zone))
Buffers: shared hit=191
-> Index Scan using documents_document_pkey on documents_document documents_access__document_id_1 (cost=0.42..2.44 rows=1 width=9) (actual time=0.001..0.001 rows=1 loops=200)
Index Cond: (id = documents_access_1.document_id)
Filter: (((access_via_link)::text <> 'none'::text) OR ((documents_access_1.role)::text = ANY ('{view,edit}'::text[])))
Rows Removed by Filter: 0
Buffers: shared hit=800
Planning:
Buffers: shared hit=56
Planning Time: 1.569 ms
Execution Time: 157.171 ms
```
portal user
before https://explain.dalibo.com/plan/e1e755fg7bb26a21
after https://explain.dalibo.com/plan/hb5fa1d201ff164g
internal user with few documents access
before https://explain.dalibo.com/plan/f753bf2aa244dg63
after https://explain.dalibo.com/plan/538dg5ecb120ch84
internal user with *lots* of documents access
before https://explain.dalibo.com/plan/cf76h84537f7ge4a
after https://explain.dalibo.com/plan/45317a5e3168c5bc
Forward-Port-Of: odoo/enterprise#120991This update simplifies the process of applying Early Payment Discounts (EPD) to refund transactions. Previously, a technical issue prevented proper mapping of tax repartition lines, now this change ensures accurate tracking and reconciliation of EPDs on refunds. This improves the reliability of financial reporting.
Original PR description
This commit does not bring native support for EPD on credit notes, only makes custom support a little easier and cleaner. It is quite easy to support EPD (early payment discounts) on refunds by…
This commit does not bring native support for EPD on credit notes, only makes custom support a little easier and cleaner. It is quite easy to support EPD (early payment discounts) on refunds by extending - `_early_payment_discount_move_types` - `_is_eligible_for_early_payment_discount` However, this approach breaks when it reaches `inverse_tax_rep` in `_get_invoice_counterpart_amls_for_early_payment_discount_per_payment_term_line`, which assumes tax repartition lines with `document_type == 'invoice'` and raises when called on `tax_rep` lines of 'refund' type instead. This commit fixes that by selecting source and target repartition lines according to the `tax_rep`'s document type, which ensures: - the `.index()` no longer raises a `ValueError`, as `tax_rep` is now looked up in the matching set (`refund_` for refunds, `invoice_` otherwise) - `inverse_tax_rep` returns the corresponding line in the opposite set, preserving the original invoice->refund mapping while adding the refund->invoice one Since `inverse_tax_rep` is a closure, downstream modules cannot patch it without copying the whole ~170-line method. Making it symmetric here lets custom EPD-on-refund support work without that duplication. task-[6265601](https://www.odoo.com/odoo/all-tasks/6265601) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#271102
The Odoo builder was experiencing performance issues due to excessive requests when the shape selector panel loaded. This fix delays the panel's content rendering until it's actually needed, preventing the UI from freezing and improving responsiveness. This change ensures a smoother user experience for builders.
Original PR description
The shape selector panel was eagerly compiling and rendering its slot content on builder startup, triggering 200+ concurrent SVG thumbnail requests before the user had opened the panel or selected an image. With browsers limiting parallel connections per domain, this flooded the request queue and caused the main UI to freeze for several seconds. Slot content is now deferred behind a `contentRendered` flag that is set the first time the panel is opened, so no compilation or network activity happens until the user actually needs it. task-5973702 Forward-Port-Of: odoo/odoo#266990 Forward-Port-Of: odoo/odoo#253041
This update automatically updates the map routes when a user moves, eliminating the need for manual refreshes. Previously, users had to trigger a refresh to see accurate routes, which was inconvenient. This change improves the user experience and ensures the map always reflects the user's location.
Original PR description
In this commit, we ensure that the map is updated with the newly computed routes if the user position changes. Prior to this commit, the user had to manually trigger an update to correctly view the updated routes.
This update fixes an issue where custom fields linked to employee/applicant records weren't being updated after a signature was completed. The fix ensures that linked fields are correctly synchronized, allowing for accurate record-keeping of signed documents. This improves data integrity within the HR and Recruitment modules.
Original PR description
Version - saas-19.3 Steps to Reproduce: 1. Create a custom Sign field (e.g. "Passport No") with "Update Field" enabled, linked to Employee (For Applicant, same any custom field). 2. Employee flow:…
Version - saas-19.3 Steps to Reproduce: 1. Create a custom Sign field (e.g. "Passport No") with "Update Field" enabled, linked to Employee (For Applicant, same any custom field). 2. Employee flow: Employee app -> open an employee -> gear icon -> Signature Request -> send. Applicant flow: Recruitment app -> Applicants list view -> select an applicant -> Actions -> Signature Request -> send. 3. Complete the signature. 4. Check the linked record's "Passport No" field -> field is not updated. Issue: The field linked to the employee/applicant record is not updated after signing. Cause: Both the `hr.contract.sign.document.wizard` and `hr.recruitment.sign.document.wizard` create the `sign.request` in `validate_signature()` without setting `reference_doc`. `_get_auto_field_target_record()` relies on `reference_doc` to resolve the record to sync auto fields against. With `reference_doc` empty, it returns `None`, so `sign.request._sync_auto_field_value()` skips the item before it ever reaches the write step. Solution: Set `reference_doc` to the corresponding `hr.employee`/`hr.applicant` record when building the `sign.request` values in `validate_signature()`, so auto fields linked to those models can resolve their target record and sync back normally after signing. taskid-6308532
This update fixes an issue where the 'Consolidation' filter wasn't visible on the General Ledger report, particularly in multi-company environments. The change ensures the filter appears based on report-level configurations, providing users with more flexibility in their reporting.
Original PR description
The Consolidation filter doesn't appear on the General Ledger, even in multi-company. Since `user_groupby` can also be defined on the `account.report`, this commit adapts the logic for `show_consolidation`, to fallback to the report's groupby. no-task
This update fixes an issue where appointment filters were incorrectly persisting when switching between views (Kanban to Gantt). Now, filters are cleared when changing views, ensuring users always see accurate appointment listings. This improves the overall user experience and data accuracy.
Original PR description
In this commit: - When switching from Kanban to Gantt view, the POS-specific filters `date_filter` and `hour_filter` (added by `PosAppointmentSearchFilter`) were persisting on the shared SearchModel, incorrectly hiding bookings. - Now these filters are removed when activating the Gantt view. - Clear these filters when changing views and add a tour test to cover the Kanban → Gantt navigation flow. Also extract common appointment view tour helpers for reuse. Task:6276594
This update strengthens the security of Odoo by ensuring users only have read access to data. This prevents potential issues and unexpected behavior within the system, safeguarding data integrity. It's a routine maintenance update focused on stability.
Original PR description
Ensure that the user has read access to prevent any unexpected behavior. Task-6226863 Forward-Port-Of: odoo/odoo#267709
This update resolves an issue where validating rental orders for products created as kits would trigger a 'record not found' error. The fix ensures that the system correctly handles the explosion of kit bills during validation, preventing this error and improving the reliability of rental order processing. This ensures rentals involving kit products function as expected.
Original PR description
### Steps to reproduce: - Enable rental transfer - Create a rentable product R - Create and confirm a rental order for 1 unit of R - Create a kit bom for R: 1 x COMP - Validate the delivery of your…
### Steps to reproduce:
- Enable rental transfer
- Create a rentable product R
- Create and confirm a rental order for 1 unit of R
- Create a kit bom for R: 1 x COMP
- Validate the delivery of your unit of R
#### > Missing Error: Record does not exist or has been deleted.
### Cause of the issue:
Confirming your rental order will generate a confirm moves of R. However, since at this point the product was not a kit, these will not be exploded. Now, the issue is that at validation The move will be exploded and deleted in the super call:
https://github.com/odoo/enterprise/blob/7cceddaf086d849b8e2121e1023ef3479397534f/sale_mrp_renting/models/stock_move.py#L10-L13 https://github.com/odoo/odoo/blob/0f2f222a431627a672daf10c86ec2578a27f97bb/addons/mrp/models/stock_move.py#L550-L555 https://github.com/odoo/odoo/blob/0f2f222a431627a672daf10c86ec2578a27f97bb/addons/mrp/models/stock_move.py#L591-L593 However, since the overrides of the sale_{mrp,stock}_renting modules call self rather than the result of the super call, they still expect to work with the original move rather than its exploded result: https://github.com/odoo/enterprise/blob/7cceddaf086d849b8e2121e1023ef3479397534f/sale_mrp_renting/models/stock_move.py#L10-L13 https://github.com/odoo/enterprise/blob/7cceddaf086d849b8e2121e1023ef3479397534f/sale_stock_renting/models/stock_move.py#L61-L65
opw-6191841
Forward-Port-Of: odoo/enterprise#120793
Forward-Port-Of: odoo/enterprise#120051This update resolves a test failure in the GCC POS module, ensuring accurate order receipt formatting. The changes include adjustments to rounding configurations and test steps to pass assertions related to discounts and change calculations. This improves the reliability of the GCC POS testing environment.
Original PR description
- Fixed `TestGenericGCC.test_generic_localization` which was failing because some information was not rendered on the order receipt. - Added rounding configuration to the POS config so that the assertion for `Rounding` does not fail. - Added steps for `Discount` and `Change` in `generic_localization_tour` so that the assertions for `Discount` and `Change` do not fail. Error-237988 Task-5897376 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#248193
This update fixes two issues related to USPS shipping rates. First, it ensures that package dimensions are displayed correctly in inches, resolving confusion for users. Second, it corrects a bug where the same rate was applied regardless of the selected shipping service, now dynamically adjusting based on the chosen USPS service type.
Original PR description
Issue ----- There are 2 issues with USPS rest: 1. USPS packagings do not have their size UOM displayed. This leads to confusion as users input in inches but the dimensions are treated as feet. 2.…
Issue ----- There are 2 issues with USPS rest: 1. USPS packagings do not have their size UOM displayed. This leads to confusion as users input in inches but the dimensions are treated as feet. 2. USPS returns the same rate regardless of the package type. Steps to reproduce ----- - Set USPS up - Open the Package Type form > go to its' Dimensions tab > Issue 1 - Set USPS up (domestic) - Select a `Domestic Rating Indicator` (eg LF - Flat Rate Box) - Create a SO with some product - Open the delivery widget and add a rate with USPS - Discard the changes - Go to the delivery method and change the rating (eg SP - Single Piece) - Go back to the SO - Open the delivery widget and add a rate with USPS > Issue 2, rate is the same as before Issue 1 ----- By default, there is no displayed UOM on the form because of https://github.com/odoo/odoo/blob/38c737c2a4cc29b48235a100cfa9d6152af73826/addons/stock_delivery/models/stock_package_type.py#L20-L33 We can change this behaviour for USPS specifically as done in Envia https://github.com/odoo/enterprise/blob/20cc61e69aa3f6a59de1e962b25ce11fa402bf22/delivery_envia/models/stock_package_type.py#L37-L46 Issue 2 ----- In `usps_rest_rate_shipment`, we request rates for every package of the delivery, which we receive as lists. We then iterate over the list to find the rate matching the `mail_class`. The problem is that this only filters over whether the delivery is domestic or international. We don't filter based on the actual service selected on the carrier (`usps_domestic_rating_indicator` for domestic and `usps_international_rating_indicator` for international). https://github.com/odoo/enterprise/blob/20cc61e69aa3f6a59de1e962b25ce11fa402bf22/delivery_usps_rest/models/delivery_usps.py#L224-L236 ----- Ticket: opw-6224918 Forward-Port-Of: odoo/enterprise#120789 Forward-Port-Of: odoo/enterprise#120594
This update fixes a discrepancy in the start date of semi-monthly payrolls. Previously, payslips were incorrectly aligned with the month's halves, leading to inaccurate pay periods. The change now ensures payslips begin on the 16th of the month, accurately reflecting the employee's pay schedule.
Original PR description
Issue: ---------------------------------------- The start date of semi-monthly payslips on second half of the month is the 15 which is also the end date of the first half of the month. Steps to reproduce: ---------------------------------------- - Have an employee with a semi-monthly payroll - When in the first half of the month, create a payslip for this employee - The payslip is from 1st to 15th - Do the same when in the second half of the month - The payslip is from 15th to end of the month Cause: ---------------------------------------- In `_schedule_period_start()` we set the start date to th 15th for semi-monthly payslips. Solution: ---------------------------------------- Set it to the 16th. opw-6281556 Forward-Port-Of: odoo/enterprise#120172
This update fixes a bug in the Preparation Time report for Point of Sale, ensuring that preparation durations are displayed correctly based on the user's current timezone. Previously, the report always used the timezone of the OdooBot, leading to inaccurate data. This change improves report accuracy and provides a more reliable view of preparation times.
Original PR description
In POS, the Preparation Time report groups average preparation durations by hour. Those hour buckets were always computed with the timezone of the user who ran the module upgrade (OdooBot /…
In POS, the Preparation Time report groups average preparation durations by hour. Those hour buckets were always computed with the timezone of the user who ran the module upgrade (OdooBot / superuser), not the timezone of the user viewing the report. Changing the user, company, or browser timezone had no effect on the graph until the module was upgraded again. Steps to reproduce: ------------------- * Configure a Preparation Display and create POS orders with measured preparation times. * Open Point of Sale → Reporting → Preparation Time. * Note the hour bucket used for the orders. * Change your user timezone in Preferences and reload the report. > Observation: The hour buckets stay the same. Before the fix, they only changed after upgrading `pos_enterprise`, because the timezone was embedded in the SQL view created during `init()` as superuser. Why the fix: ------------ Replace the static PostgreSQL view with a dynamic `_table_query` so `order_hour` is computed with the current user's timezone on each report read. `init()` now only drops the legacy view instead of recreating it with a frozen timezone. opw-6220248 Forward-Port-Of: odoo/enterprise#118365
This fix ensures that credit notes for returned dropshipped products accurately display the correct lot/serial number on the invoice report. Previously, the system incorrectly used a different lot number, now it correctly reflects the returned product's lot.
Original PR description
**Issue** Printing a credit note for a returned dropshipped tracked product could display the wrong lot/serial number on the invoice report. **Steps to reproduce** - Activate "Display Lots & Serial…
**Issue**
Printing a credit note for a returned dropshipped tracked product could display the wrong lot/serial number on the invoice report.
**Steps to reproduce**
- Activate "Display Lots & Serial Numbers on Invoices"
- Create a product tracked by serial/lot and enable the dropship route
- Create two lots: "lot1" and "lot2"
- Create and confirm a SO for quantity 2
- Confirm the PO and validate the dropship for both lots
- Create and post an invoice
- Return "lot2" from the dropship picking
- Create and post a credit note for quantity 1
- Click on print -> The generated PDF displays "lot1" instead of "lot2"
**Cause**
While rendering `account.report_invoice_with_payments`, the report calls `_get_invoiced_lot_values` to determine which lot/serial numbers should be displayed:
https://github.com/odoo/odoo/blob/786c373d5ac8afdfb79eb7a7d69c5eb83b919625/addons/sale_stock/models/account_move.py#L31-L32 `invoiced_qties = 1` since the credit is on a quantity of 1 https://github.com/odoo/odoo/blob/786c373d5ac8afdfb79eb7a7d69c5eb83b919625/addons/sale_stock/models/account_move.py#L44 Three stock move lines are retrieved from the SO:
- the two original dropship deliveries,
- the return move for `lot2`. https://github.com/odoo/odoo/blob/786c373d5ac8afdfb79eb7a7d69c5eb83b919625/addons/sale_stock/models/account_move.py#L63 However, none of them are considered as `is_stock_return` because the dropship locations use `supplier` instead of `internal`: https://github.com/odoo/odoo/blob/786c373d5ac8afdfb79eb7a7d69c5eb83b919625/addons/sale_stock/models/account_move.py#L72-L76 As a consequence:
- The two original delivery move lines each keep quantity `1`: https://github.com/odoo/odoo/blob/786c373d5ac8afdfb79eb7a7d69c5eb83b919625/addons/sale_stock/models/account_move.py#L69 they never pass through the return handling logic: https://github.com/odoo/odoo/blob/786c373d5ac8afdfb79eb7a7d69c5eb83b919625/addons/sale_stock/models/account_move.py#L77-L80 which would make it as -1 (since `qties_per_lot[sml.lot_id]` is 0 for the first iteration of `sml.lot_id`). Thus, it does not pass by this code (since quantity is greater than 0): https://github.com/odoo/odoo/blob/786c373d5ac8afdfb79eb7a7d69c5eb83b919625/addons/sale_stock/models/account_move.py#L87-L90 which would make it as 0.
- for the last one, `is_stock_return = False` as it should be, thus the quantity is 1 as it should be. The quantities are therefore accumulated as:
https://github.com/odoo/odoo/blob/786c373d5ac8afdfb79eb7a7d69c5eb83b919625/addons/sale_stock/models/account_move.py#L92
resulting in:
`qties_per_lot = {lot1: 1, lot2: 2}`
instead of:
`qties_per_lot = {lot1: 0, lot2: 1}`
The report then selects the first matching lot and stops: https://github.com/odoo/odoo/blob/786c373d5ac8afdfb79eb7a7d69c5eb83b919625/addons/sale_stock/models/account_move.py#L94-L99
opw-6230281
Forward-Port-Of: odoo/odoo#266716This update resolves an issue where demo data installation for the Russian localization module (`l10n_in`) failed when installed without pre-existing demo data. The fix ensures that company IDs are correctly converted into the required format, allowing users to successfully load demo data through the Settings menu.
Original PR description
## Description When loading demo data from **Settings** after installing `l10n_in` without demo data, the `_install_demo` method receives company IDs instead of a `res.company` recordset. As a…
## Description When loading demo data from **Settings** after installing `l10n_in` without demo data, the `_install_demo` method receives company IDs instead of a `res.company` recordset. As a result, the following line crashes: ```python companies.filtered(...) ``` with: ```text AttributeError: 'int' object has no attribute 'filtered' ``` This PR ensures that the received company IDs are converted into a `res.company` recordset before being processed, allowing demo data to be loaded successfully from the Settings menu. ## Steps to Reproduce 1. Install `l10n_in` **without demo data**. 2. Navigate to **Settings**. 3. Click **Load Demo Data**. ## Current Behavior Demo data installation fails with: ```text AttributeError: 'int' object has no attribute 'filtered' ``` ## Expected Behavior Demo data should be installed successfully without raising any exception. ## Solution Convert the received company IDs into a `res.company` recordset when the argument passed to `_install_demo` is not already a recordset. Forward-Port-Of: odoo/odoo#270523
This update fixes an issue where changing a company's country caused errors in Time Off management. Previously, Time Off records were linked to the old country, leading to access problems. Now, the system prevents country changes unless there are no related Time Off records, ensuring smoother operations.
Original PR description
When a Time Off Type is created, it inherits the country of the current company. If there are leaves or allocations created from this Time Off Type and the company's country is then changed, various…
When a Time Off Type is created, it inherits the country of the current company. If there are leaves or allocations created from this Time Off Type and the company's country is then changed, various parts of Time Off will throw access errors as the leaves and allocations are still tied to the former country. The goal of this PR is to constrain the company country from being changed unless there are no such leaves or allocations. **Steps to Reproduce on Runbot:** 1. Ensure the current company has a `country` set, e.g. "My Company (San Fransisco)" has country set to "United States". 2. Access Time Off as Mitchell Admin. 3. Create a new Time Off Type, for simplicity's sake without a need for allocation or approval, ex: "Gone Fishing". Note this Time Off Type will have the `country` set to the company country by default. 4. Take "Gone Fishing" time off. 5. Change or set blank the company's `country` value. 6. Ensure the record rules cache is flushed. 7. Try to access Time Off. opw-6206359, opw-6140496 closes #263950 Forward-Port-Of: odoo/odoo#270270 Forward-Port-Of: odoo/odoo#263950
This update resolves an issue where saving a job page description with all content removed resulted in a 'Document is empty' validation error. The fix ensures that empty, whitespace-only HTML fields are handled correctly during saving, preventing the error and allowing users to successfully update job page descriptions. This improves the user experience and prevents data loss.
Original PR description
Steps to reproduce: =================== 1. Edit a job page. 2. Delete every `s_rating` block. 3. Save. => Validation Error: Document is empty. Cause: ====== Deleting the last snippet inside an…
Steps to reproduce: =================== 1. Edit a job page. 2. Delete every `s_rating` block. 3. Save. => Validation Error: Document is empty. Cause: ====== Deleting the last snippet inside an editable HTML field (e.g. the last `s_rating` block in the `website_rating` field of a job page) leaves the field's editable container with only whitespace text nodes. On save, it writes that whitespace to the record and then calls `_copy_custom_snippet_translations`, which does `html.fromstring(lang_value)` on the whitespace and raises `lxml.etree.ParserError: Document is empty`, re-raised as `ValidationError`. The user sees a "Validation Error" dialog and can't finish saving. The previous fix for the analogous "Document is empty" symptom on product description editing (commit [1]) added a `cleanupEmptyStructures` `on_removed_handlers` that strips whitespace from `.oe_empty` containers after element removal. That selector covers `oe_structure.oe_empty` containers but not editable HTML field savables (`[data-oe-type="html"]`), which don't carry an `oe_empty` class when they originally had content. As a result, fields like `hr.job.website_rating` still hit the failing parse path. Solution: ========= Extend the cleanup selector to also include `[data-oe-type="html"]` so HTML-field editables are normalized to genuinely empty after the last inner snippet is removed. [1]: https://github.com/odoo/odoo/commit/53d5cc7eed635f64038bf0315f6863011879c529 opw-6244892 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#270466 Forward-Port-Of: odoo/odoo#267397
Documentation and clarification updates
This pull request formally records Adrien Didot's signature on the Odoo Individual Contributor License Agreement. It adds documentation confirming the CLA signing, ensuring compliance with Odoo's licensing terms. This update is a standard legal step for contributors to the Odoo project.
Original PR description
Individual Contributor License Agreement signature. Adds `doc/cla/individual/adridot.md` per the CLA signing instructions. Related contribution: #270196 Forward-Port-Of: odoo/odoo#270411 Forward-Port-Of: odoo/odoo#270197
13 changes
Resolved issues and error corrections
This update fixes a reporting issue where Preparation Time reports displayed incorrect hour buckets due to using the OdooBot's timezone instead of the user's. Now, reports accurately reflect preparation times based on the user's local timezone, ensuring consistent and reliable data for business analysis.
Original PR description
In POS, the Preparation Time report groups average preparation durations by hour. Those hour buckets were always computed with the timezone of the user who ran the module upgrade (OdooBot /…
In POS, the Preparation Time report groups average preparation durations by hour. Those hour buckets were always computed with the timezone of the user who ran the module upgrade (OdooBot / superuser), not the timezone of the user viewing the report. Changing the user, company, or browser timezone had no effect on the graph until the module was upgraded again. Steps to reproduce: ------------------- * Configure a Preparation Display and create POS orders with measured preparation times. * Open Point of Sale → Reporting → Preparation Time. * Note the hour bucket used for the orders. * Change your user timezone in Preferences and reload the report. > Observation: The hour buckets stay the same. Before the fix, they only changed after upgrading `pos_enterprise`, because the timezone was embedded in the SQL view created during `init()` as superuser. Why the fix: ------------ Replace the static PostgreSQL view with a dynamic `_table_query` so `order_hour` is computed with the current user's timezone on each report read. `init()` now only drops the legacy view instead of recreating it with a frozen timezone. opw-6220248 Forward-Port-Of: odoo/enterprise#118365
This update resolves a bug preventing Avatax exemption code synchronization. The issue stemmed from AvaTax returning '*' to indicate all countries, which was incorrectly interpreted as 'False' by the system. This fix ensures correct country ID handling, allowing successful synchronization and improved functionality.
Original PR description
Steps to reproduce: - Create a US company - Go to Accounting > Configuration > Settings - Activate `Avatax` > Set Credentials - Try to "Sync Parameters" Traceback: ```py File…
Steps to reproduce:
- Create a US company
- Go to Accounting > Configuration > Settings
- Activate `Avatax` > Set Credentials
- Try to "Sync Parameters"
Traceback:
```py
File "/home/odoo/src/enterprise/saas-19.2/account_avatax/models/res_company.py", line 113, in avatax_sync_company_params
'valid_country_ids': [(6, 0, get_countries(vals['validCountries']).ids)],
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/enterprise/saas-19.2/account_avatax/models/res_company.py", line 90, in get_countries
return self.env['res.country'].browse([country_cache[code] for code in code_list])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/saas-19.2/odoo/orm/models.py", line 5208, in browse
assert all(ids) or all(isinstance(x, NewId) or x for x in ids), "Invalid falsy real id"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: Invalid falsy real id
```
The issue occurs because AvaTax return `*` in the `validCountries` field to indicate that an exemption code is valid for all countries. The synchronization logic stores this value in the country cache as `False` and later passes it to `res.country.browse()`. Since `browse()` does not accept a mix of valid IDs and falsy values, the operation crashes during the synchronization process.
This commit filter out falsy country IDs when resolving country codes to prevent crashes and allow exemption codes to be synchronized successfully.
opw-6298189
Forward-Port-Of: odoo/enterprise#120845This update prevents users from changing the status of checks when they don't have the necessary permissions. Previously, attempting to modify a check without selecting the main company would result in an error. Now, the status change button is disabled, ensuring data integrity and preventing unintended actions.
Original PR description
Before this commit: Only main company of tax unit have write access on check, so when main company is not selected and user tries to change status of check, access error is thrown. After this commit: Disable check status button if user don't have write access on check. task-5951364 Forward-Port-Of: odoo/odoo#271330
This update fixes a previous issue where self-order receipts lacked important company information like the logo, address, and contact details. Now, all relevant company and PoS settings are included on self-order receipts, improving customer experience and brand consistency.
Original PR description
Before this commit: ---------------- - Order receipts generated from self-orders were missing several company and PoS configuration details, such as the company logo, receipt address, phone number, email, and website. After this commit: ---------------- - Order receipts generated from self-orders now include all relevant company and PoS configuration details. Task-6271261
This update resolves an issue where the 'deliver' button wouldn't appear on sales orders without a product line. Previously, this prevented users from fulfilling orders when the stock module wasn't installed. The change ensures that all sales order lines, including those without products, correctly calculate delivery quantities.
Original PR description
In saas-19.2, note lines on SO's are no longer have a calculated
"manual" qty_delivered_method value. In the previous code, these would
prevent the deliver button showing on SO's (when stock was not
installed). These would also cause issues with the deliver action.
On Runbot (no apps installed):
1. Install Sales
2. Create SO with a product
3. Confirm SO
4. See deliver button dissapear
This change will correct a previous change so that sale order lines without a product will remain with a manual delivered method
opw-6280551
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prThis update resolves a problem where users were incorrectly denied access to WhatsApp templates within the Event module. The fix prevents users from creating new WhatsApp templates, which was causing the 'User does not have access' error. This ensures proper WhatsApp communication functionality.
Original PR description
Issue: 1) User goes to Event.event Form -> communication tab -> add line 2) Select whatsapp -> type something -> create and edit -> create new template with any model event.registration -> save ( all the way including the event form) 3) reload page -> whatsapp event.mail displays "User does not have access to this record". Fix: add "'no_create_edit': True" to the associated field in the xml to block creation of new mail.templates opw-6037488 Forward-Port-Of: odoo/odoo#268641 Forward-Port-Of: odoo/odoo#259683
This update resolves an issue where loading demo data after installing the `l10n_in` module without pre-existing demo data would fail. The fix ensures that company IDs are correctly converted into a usable recordset, allowing users to successfully load demo data from the Settings menu. This improves the user experience and ensures consistent demo data setup.
Original PR description
## Description When loading demo data from **Settings** after installing `l10n_in` without demo data, the `_install_demo` method receives company IDs instead of a `res.company` recordset. As a…
## Description When loading demo data from **Settings** after installing `l10n_in` without demo data, the `_install_demo` method receives company IDs instead of a `res.company` recordset. As a result, the following line crashes: ```python companies.filtered(...) ``` with: ```text AttributeError: 'int' object has no attribute 'filtered' ``` This PR ensures that the received company IDs are converted into a `res.company` recordset before being processed, allowing demo data to be loaded successfully from the Settings menu. ## Steps to Reproduce 1. Install `l10n_in` **without demo data**. 2. Navigate to **Settings**. 3. Click **Load Demo Data**. ## Current Behavior Demo data installation fails with: ```text AttributeError: 'int' object has no attribute 'filtered' ``` ## Expected Behavior Demo data should be installed successfully without raising any exception. ## Solution Convert the received company IDs into a `res.company` recordset when the argument passed to `_install_demo` is not already a recordset. Forward-Port-Of: odoo/odoo#270523
This update resolves an issue where saving a job page description with only whitespace resulted in a validation error. The fix ensures that empty HTML fields are handled correctly during saving, preventing the 'Document is empty' error and allowing users to successfully update their job postings. This improves the user experience and prevents data loss.
Original PR description
Steps to reproduce: =================== 1. Edit a job page. 2. Delete every `s_rating` block. 3. Save. => Validation Error: Document is empty. Cause: ====== Deleting the last snippet inside an…
Steps to reproduce: =================== 1. Edit a job page. 2. Delete every `s_rating` block. 3. Save. => Validation Error: Document is empty. Cause: ====== Deleting the last snippet inside an editable HTML field (e.g. the last `s_rating` block in the `website_rating` field of a job page) leaves the field's editable container with only whitespace text nodes. On save, it writes that whitespace to the record and then calls `_copy_custom_snippet_translations`, which does `html.fromstring(lang_value)` on the whitespace and raises `lxml.etree.ParserError: Document is empty`, re-raised as `ValidationError`. The user sees a "Validation Error" dialog and can't finish saving. The previous fix for the analogous "Document is empty" symptom on product description editing (commit [1]) added a `cleanupEmptyStructures` `on_removed_handlers` that strips whitespace from `.oe_empty` containers after element removal. That selector covers `oe_structure.oe_empty` containers but not editable HTML field savables (`[data-oe-type="html"]`), which don't carry an `oe_empty` class when they originally had content. As a result, fields like `hr.job.website_rating` still hit the failing parse path. Solution: ========= Extend the cleanup selector to also include `[data-oe-type="html"]` so HTML-field editables are normalized to genuinely empty after the last inner snippet is removed. [1]: https://github.com/odoo/odoo/commit/53d5cc7eed635f64038bf0315f6863011879c529 opw-6244892 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#270466 Forward-Port-Of: odoo/odoo#267397
This update corrects an issue where the FEC export file generated for French companies sometimes contained empty lines with zero balances. This prevented accurate financial reporting and data exchange with tax authorities. The fix ensures all accounts have a valid balance when exporting, improving data reliability.
Original PR description
Steps to reproduce: - Use a French company (l10n_fr_account installed) - Post prior-year entries so that an account/partner nets to zero at the start of the next fiscal year (e.g. a customer invoice fully paid the same year, or a misc entry debiting and crediting the same balance-sheet account), and keep another account/partner with a non-zero opening - Open the FEC export wizard, set Start Date to the first day of the next year - Generate the FEC file and look at the "Balance initiale" (OUVERTURE) lines Issue: One of the exported line in as empty one with `...|0,00|0,00|..`` opw-6083991 Forward-Port-Of: odoo/odoo#270658 Forward-Port-Of: odoo/odoo#268510
This update fixes a minor UX issue where the spreadsheet filter dropdown remained open even when the selected filter value hadn't changed. The fix ensures the dropdown automatically closes after the filter button is clicked, providing a more consistent and intuitive user experience. This improves usability and reduces potential confusion for users.
Original PR description
Current behavior before PR: - In b4d5d1f, added early return when filter value is unchanged. - However, the dropdown was not closed in this case, leaving it open after clicking the filter button, resulting in inconsistent and unexpected UX. Desired behavior after PR is merged: - Ensure the dropdown is closed even when the filter value remains unchanged, restoring consistent and expected behavior. Task: [6304213](https://www.odoo.com/odoo/project/2328/tasks/6304213) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#270225
This update fixes an issue where the total invoice amount was not being displayed correctly in the order view. The change reintroduces a key field, ensuring accurate invoice amounts are shown to users. This improves clarity and accuracy in sales reporting.
Original PR description
This is a backport of 953e92b8bd79a39042c78ca7183ae73f90906c1e. `amount_to_invoice` is a technical field only used to trigger the credit limit warning on invoices/SOs and is not supposed to be shown in views. 6feba7b018e15738be145ce48be9761481e9e11a opw-6271335 Forward-Port-Of: odoo/odoo#270250
This update fixes an issue where clicking on an employee's avatar in the Discuss section displayed outdated information from archived records. The fix ensures that the correct, current employee details are shown, resolving a display inconsistency. This improves the user experience when accessing employee information.
Original PR description
*: hr_holidays,test_discuss_full **Steps to reproduce,** Create an employee linked to a user Archive the employee and remove the link to the user Create another employee for the same user Go to…
*: hr_holidays,test_discuss_full **Steps to reproduce,** Create an employee linked to a user Archive the employee and remove the link to the user Create another employee for the same user Go to Discuss > 'General' channel Open the member list and click on the user's avatar **Before this commit,** Clicking on the avatar opened a popover showing outdated information from the archived employee record instead of the new one. **Cause,** By default, the server sends employee data ordered by name. Since both records have the same name, the order is non-deterministic. The client then attempts to match the employee's company to the current user's company, falling back to the first record in the list if no match is found. **Fix,** Filter out archived records first (treating them as non-existent). Then, sort the remaining employee records to prioritize those that match the current user's active company. In case records share the same company, prioritize employees with a related user. Fall back to descending order of creation for identical results. **After this commit,** Clicking on the avatar shows the correct employee details in the popover. task-6175765 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#270169 Forward-Port-Of: odoo/odoo#252170
This update resolves an issue related to how Odoo handles direct debit mandates for partner banks. The change adds a crucial check to ensure that direct debit setups are only processed against valid bank accounts, enhancing security and reliability. This improves the accuracy of payment processing for SEPA direct debit transactions.
Original PR description
Forward-Port-Of: odoo/enterprise#121236 Forward-Port-Of: odoo/enterprise#120901
4 changes
Resolved issues and error corrections
This update prevents users from changing the status of checks when they lack the necessary permissions. Previously, users without access to the main company of a tax unit would encounter errors. Now, the status change button is disabled, ensuring data integrity and preventing incorrect status updates.
Original PR description
Before this commit: Only main company of tax unit have write access on check, so when main company is not selected and user tries to change status of check, access error is thrown. After this commit: Disable check status button if user don't have write access on check. task-5951364 ENT PR: https://github.com/odoo/enterprise/pull/121353
A recent issue prevented users from creating WhatsApp event templates, resulting in an 'access denied' error. This fix restricts the creation of new WhatsApp templates, ensuring users can only manage existing ones. This resolves a bug impacting event communication workflows.
Original PR description
Issue: 1) User goes to Event.event Form -> communication tab -> add line 2) Select whatsapp -> type something -> create and edit -> create new template with any model event.registration -> save ( all the way including the event form) 3) reload page -> whatsapp event.mail displays "User does not have access to this record". Fix: add "'no_create_edit': True" to the associated field in the xml to block creation of new mail.templates opw-6037488 Forward-Port-Of: odoo/odoo#268641 Forward-Port-Of: odoo/odoo#259683
This update fixes an issue where the spreadsheet filter dropdown remained open even when the selected filter value didn't change. The change ensures the dropdown automatically closes after a filter selection, providing a more consistent and user-friendly experience. This improves usability and reduces confusion for users.
Original PR description
Current behavior before PR: - In b4d5d1f, added early return when filter value is unchanged. - However, the dropdown was not closed in this case, leaving it open after clicking the filter button, resulting in inconsistent and unexpected UX. Desired behavior after PR is merged: - Ensure the dropdown is closed even when the filter value remains unchanged, restoring consistent and expected behavior. Task: [6304213](https://www.odoo.com/odoo/project/2328/tasks/6304213) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#270225
This update fixes an issue where product pricing in the Point of Sale (PoS) system was incorrectly calculating VAT and total prices. The fix ensures that prices accurately reflect the applied pricelist and fiscal position mappings, resulting in correct tax calculations and total amounts.
Original PR description
Steps to reproduce: ------------------- 1. Create a product with a tax (e.g. 15%). 2. Create a pricelist that changes the price (e.g. 100 to 200). 3. Create a fiscal position mapping the tax (e.g.…
Steps to reproduce: ------------------- 1. Create a product with a tax (e.g. 15%). 2. Create a pricelist that changes the price (e.g. 100 to 200). 3. Create a fiscal position mapping the tax (e.g. 15% to 30%). 4. Add the pricelist and the fiscal position in PoS. 5. Add the product to the cart, and select the tax and the pricelist created in the previous steps. 6. Long press on the product to see its info. The price should be 200 now after selecting the pricelist. Also the tax should be 30% bc of the FP mapping, i.e. total price should be 200 + 30% = 260. However, we observe that VAT shows 15 (15%) instead of 60 (30%), and Price incl. Tax shows 230 instead of 260. What's happening: ----------------- On the frontend, `getTaxDetails()` is called with no options, so it uses the product `list_price` (100) and `taxes_id` (15%), giving VAT = 15. Alos, on the backned, `self.taxes_id` is used directly to compute the taxes, even though the pricelist price is correct (200), fiscal position is ignored, hence 200 + 15% = 230 instead of 200 + 30% = 260. The fix: -------- On frontend, we pass the pricelist and fiscal position to `getTaxDetails`, and compute the tax name from the mapped taxes. On the backend, we read the `fiscal_position_id` from the context and apply the tax mapping, so the correct taxes are used. opw-6200632 Forward-Port-Of: odoo/odoo#266012
1 change
Resolved issues and error corrections
This update corrects an issue with unnecessary rounding in the Switzerland payroll calculations. The fix utilizes Odoo's built-in rounding function to ensure accurate pay calculations, specifically addressing discrepancies related to floating-point math. This improves the reliability of payroll reports for Swiss users.
Original PR description
Before this commit, unecessary extra rounding was done due to float math being float math. https://github.com/odoo/enterprise/blob/0a1f11e45f455a87d54fcac7e3e65274e29c619e/l10n_ch_hr_payroll/models/hr_payslip.py#L196-L198 We can see the issue by: 1. Open a python terminal 2. Type in 1000 % 0.05 >= 0.025 3. See result is true but this should not be true To fix this we use the built in float_round **Exists in 18.4 to master** opw-6322937
1 change
Resolved issues and error corrections
This update fixes an issue where preparation times weren't accurately calculated when order stages changed, and reports incorrectly combined data across all companies. The changes ensure preparation times are correctly updated and that reports now display data specific to the active company, leading to more accurate order time estimations and reporting.
Original PR description
Issues: - Preparation time for order lines was not computed when the preparation order stage changed. - Preparation time report aggregated orders across all companies instead of showing records for the active company only. Fixes: - Ensure preparation time is properly recomputed when the order stage changes. - Add company domain filtering to the preparation time report. Task-6250974
15 changes
New functionality added to Odoo
This update introduces an AI-powered tool to automatically rename documents, streamlining document management. The previous demo tool has been removed, and the new system uses a standardized naming convention ([ORIGIN]-[SENDER]-[DOC_TYPE]-[DATE]) to ensure consistent document organization. This improves data clarity and efficiency.
Original PR description
This commit introduces a new AI-powered tool for automatically renaming documents, replacing the previous demo tool which has been removed along with its data. Key changes: - Added a standard default prompt for document renaming that follows the naming convention: [ORIGIN]-[SENDER]-[DOC_TYPE]-[DATE]. - Removed the obsolete demo renaming tool and its associated demo data. - Updated demo data of `documents_ai` bridges to make the demo prompt more readible task-5860839
This update adds the ability to generate a required CSV export for the Oman Wage Protection System (WPS) from payroll runs. This allows businesses to comply with Omani regulations by providing the necessary data in the correct format for reporting to the MOL. The report includes details for both employers and employees, streamlining the payroll reporting process.
Original PR description
Adds support for generating the Oman Wage Protection System (WPS) CSV export from payroll batch runs, along with the configuration fields and payslip validation it requires.
The payment report wizard gains a new l10n_om_wps format that generates a CSV with an employer section (MOL numbers, bank short name, IBAN, period, totals) and an employee section (ID, bank details, salary breakdown, extra hours, notes). Bank code resolution prefers the account's WPS Short Name and falls back to a hardcoded BIC to code table covering all Omani banks. The filename follows SIF_{MOL}_{BankCode}_{YYYYMMDD}_{NNN} with a daily-resetting 3-digit counter.
task-6040641Enhancements to existing features
This update simplifies how prices with taxes (included or excluded) are managed within Odoo. Users can now dynamically adjust tax settings on invoices, orders, and purchase orders, reducing the risk of duplicate taxes and improving overall financial accuracy. However, be aware of potential complexities when overridden tax settings are in place.
Original PR description
### Purpose To improve management of prices with tax included and tax excluded. To simplify handling a mix of both in the same company and avoiding duplicate taxes. ### Implementation Users can…
### Purpose To improve management of prices with tax included and tax excluded. To simplify handling a mix of both in the same company and avoiding duplicate taxes. ### Implementation Users can change default taxes into included or excluded in the prices dynamically on account.move, sale.order and purchase.order. This is done through a selection field document_tax_mode that allows the user to set any default taxes on the lines to tax included or excluded. This will be reflected on the total amounts of the document. Taxes with an override tax mode set (price_include_override on account.tax) will keep their overridden behavior regardless of the document tax mode. Beware of functionally non-applicable cases with overridden taxes that can lead to erratic behavior: -company tax mode set to tax included, with a tax included override tax, document set to tax excluded, -company tax mode set to tax excluded, with a tax excluded override tax, document set to tax included. odoo/odoo/pull/251800 odoo/upgrade/pull/9951 task-5942016
This update enhances the payroll experience for employees classified as 'company executives.' Specifically, it adds support for a 'joint committee' of 999 and hides irrelevant fields (sub-type, dimona category, and flat rate) to simplify data entry and improve usability. This change aligns with user needs and streamlines the payroll process.
Original PR description
This PR expected to - Add the joint committee 999 on the employee type 'company executive' - If the join committee of the employee is 999: - Hide the field sub-type and make sure it's empty - Hide the field dimona category and make sure it's empty task: 6300301
This update simplifies the systray check-in process by aligning it with backend attendance settings. Previously, check-in was triggered by attendance status, but now it's controlled solely through backend configurations. This change streamlines the process and reduces complexity.
Original PR description
[IMP] hr_work_entry_attendance: systray check_in appearance adjustment Systray check-in was available when the employee or user is attendance based but now, it will only depends on attendance check-in from backend setting. So, no need to look to attendance_based now. task - 6309593
This update enhances the user experience for payroll reports in the Belgian HR module. Now, users can preview reports as PDFs, even for batch reports, and the 'Eligible Employee' button directly navigates to the employee's profile, streamlining workflows.
Original PR description
1. Display the preview button even for batch reports. When clicking on it, a PDF appears: it is the same PDF that would be shown if we previewed the report as web. 2. From the Eligible Employee smart button, allow the user to navigate to the employee profile. __ task-6304028
This update enhances the customer display within our POS apps (enterprise, IoT, and mobile) by incorporating dark mode assets and streamlining URL calculations. By centralizing the URL computation, we've reduced redundancy and improved the overall consistency of the customer display across all POS experiences. This change ensures a better user experience and simplifies future updates.
Original PR description
pos*: pos_enterprise, pos_iot, pos_mobile - Add proper dark mode assets for the customer display (aligned with POS styling) - Centralize customer display URL computation in the PoS store service to avoid code duplication Task-6139178 Related PRs: - https://github.com/odoo/odoo/pull/260331
This update improves reporting for Belgian payroll runs by renaming and reorganizing key data fields. Specifically, it adds information on NSSO contributions and withholding taxes, providing a more complete picture of Belgian pay run data. This change is limited to the Belgium localization.
Original PR description
This PR expected only applies to Belgium Localization. There are fews changes in this view: - Rename Employer cost to Total Cost - Remove Gross - Add NSSO Contribution - Add Witholding taxes This changes to provide important information on belgian pay run task: 6290433
This update simplifies the process of creating Quality Alerts directly from Manufacturing Orders, making it easier for users to report issues. The form has been redesigned with a clearer layout and streamlined fields, reducing unnecessary complexity. This change improves efficiency and data accuracy when managing quality control.
Original PR description
Users cannot easily create a Quality Alert directly from a Manufacturing Order (MO), and the Quality Alert form exposes fields that are unnecessary or unclear depending on the context. This commit…
Users cannot easily create a Quality Alert directly from a Manufacturing Order (MO), and the Quality Alert form exposes fields that are unnecessary or unclear depending on the context. This commit improves alert creation from MOs and refines the form behavior. This commit's changes: - Add an action on the Manufacturing Order form to create a Quality Alert directly from the Action menu. - Simplify the Quality Alert form header and move the priority widget to the top of the form. - Show "Title..." as the Title field placeholder for new alerts, then use the Quality Alert reference once assigned if no title was entered. - Remove the Product Template field from the quality.alert model. - Rename the Product Variant field label to "Product". - Update the form to show either the Picking or Manufacturing Order, hiding the unused field. - Rename the "Lot" field to "Lot/Serial". - Show the "Lot/Serial" field only when the selected product is tracked by lot or serial number. - Add "allowed_lot_ids" to identify lots/serials linked to the current Manufacturing Order or Picking. - Restrict "Lot/Serial" selection to "allowed_lot_ids" when available; otherwise fall back to all lots of the selected product. - Hide the Work Center field on the form unless it is set. task-6102168
Resolved issues and error corrections
This update resolves an issue preventing accurate wage calculations within the Chinese payroll module. The fix corrects a domain filter, ensuring that the correct wage types are applied to employee payrolls. This ensures payroll processing is functioning as intended.
Original PR description
Oversight of c2f18f3de7ebaa418ae24b73dd4be7483972bbaf
A recent update altered how Odoo designates the default website based on sequence number. This change caused a test to fail because a newly created website was incorrectly set as the default. This commit resolves the test by adjusting the website sequence number, ensuring the test continues to run successfully.
Original PR description
The community PR connected to this PR changed the website behaviour such that the website with the lowest sequence is considered to be the default one. After this change, `test_helpdesk_team_visibility` fails. This happens because the test creates a website with the lowest sequence number which now immediately becomes the default one. This was not intended, and it breaks the test. This commit fixes the test by using an higher sequence number such that the newly created website does not get set as the default website. Community PR: https://github.com/odoo/odoo/pull/225335 Upgrade PR: https://github.com/odoo/upgrade/pull/9434 task-5028180
This update fixes an issue where payroll reports (specifically the 281.10 PDF) were cutting text in half, making them difficult to read. The changes ensure that data rows remain intact on a single page, resulting in a more professional and easily understandable report layout. This improves the clarity and accuracy of payroll documentation.
Original PR description
The PDF engine cuts text in half when a row hits a page break, making it unreadable. Forced breaks also leave unnatural gaps. This ensures rows stay intact on a single page and allows the document to paginate naturally. task-6316335
This update resolves a minor issue with the Enterprise version of Odoo's VoIP system. Specifically, it adapts the system to ensure proper subscription handling during startup, improving reliability. This change ensures a smoother and more stable experience for users.
Original PR description
Enterprise counter-part. https://github.com/odoo/odoo/pull/270281
This update resolves a problem where the point-of-sale tour was incorrectly proceeding before order preparation data was fully synchronized. This prevented accurate testing and could lead to inconsistent results. The fix ensures preparation synchronization completes before the tour continues, improving the reliability of the testing process.
Original PR description
The `applyBestComboMultiQty` tour was proceeding before the order synchronization and preparation requests had completed. This introduced timing-related inconsistencies in `test_apply_best_combo_multi_qty`, causing assertions to occasionally run against incomplete data. Add the required `waitRequest` steps to ensure preparation synchronization is finished before advancing to the next tour actions. Runbot Error-[939058](https://runbot.odoo.com/odoo/error/939058)
Code cleanup and technical improvements
This update enhances the process of printing shipping labels and documents by supporting direct printing via ePOS and Zebra printers, eliminating the need for IoT devices. Additionally, the system has been refactored to reduce code duplication within the stock delivery module, improving efficiency.
Original PR description
We now allow printing Shipping Labels/Documents using ePOS protocol (e.g. EPSON TM-L100) and Zebra ZPL network printers to avoid using IoT. We then moved some the chatter search of documents in `stock_delivery` to avoid duplicating code. see odoo/odoo#248509 task-4599220
6 changes
Enhancements to existing features
This update allows administrators to control when payslip PDFs are generated and emailed to employees – options include automatic delivery on validation or payment, or manual delivery. Previously, this setting was managed differently, requiring a migration script. This change simplifies management and avoids disruption for existing users.
Original PR description
Backport of odoo/enterprise#97957 adapted for stable 19.0 policy.
This commit adds a global setting that controls when payslip PDFs are generated and emailed to employees: on validation, on payment, or never (manual). The three modes are exposed in Payroll settings.
Difference from 19.1: the trigger is stored in ir.config_parameter ('hr_payroll.payslip_generate_and_send_trigger') instead of a new column on res.company, avoiding any migration script. When the parameter is absent the behaviour falls back to 'on_confirmed', preserving the existing behaviour for all current installations.
task-6268644Resolved issues and error corrections
This update resolves an issue where changes to roles within duplicated sign templates were unintentionally reflected across all instances. By copying the role data when duplicating a sign item, each template now has its own independent roles, ensuring data consistency and preventing conflicts.
Original PR description
When duplicating a sign template, its sign items were copied but their `responsible_id` was kept as a reference to the same `sign.item.role` records. As a result, editing a role on one template (e.g. assigning a partner through `assign_to`) leaked to the other template sharing it. Copy the role when copying a sign item so each template owns its own roles. task-6288951
This update removes an unnecessary 'external' tag from the SendCloud delivery module's tests. Previously, errors were only detected during nightly builds, not by the standard Continuous Integration process. Removing the tag now ensures all tests run correctly and efficiently.
Original PR description
Test class was tagged as external although calls are mocked. This means errors were only caught in nightly and not by CI. Removing the tag requires fixing some of the tests. For `test_multicollo`, we send the average weight of packages instead of the total since 97f82442c9fee7dcb3e8c5e9bacddcd6bb864e11. Forward-Port-Of: odoo/enterprise#118386 Forward-Port-Of: odoo/enterprise#111660
This update significantly speeds up the loading of large General Ledger reports by optimizing how display names are retrieved. Previously, the system loaded unnecessary data, leading to slow performance. Now, a single fetch call efficiently retrieves only the required display name information, dramatically reducing memory usage and improving loading times.
Original PR description
### Issue Loading a large General Ledger (e.g., during an "Unfold All" action) and retrieving display names for thousands of journal lines (`account.move.line`) causes excessive memory and…
### Issue Loading a large General Ledger (e.g., during an "Unfold All" action) and retrieving display names for thousands of journal lines (`account.move.line`) causes excessive memory and performance overhead. Profiling with `memray` showed that one of the main memory hotspots was located in `custom_label_builder`. **Previous behavior:** Accessing `record.display_name` in a loop without an explicit `fetch()` call triggered lazy computation of the field via `_compute_display_name()`. When the compute method accessed stored dependency fields (such as `name`, `ref`, `move_id`), each cache miss went through `_fetch_field()`, which greedily loaded **all fields sharing the same prefetch group** on the model, far beyond the dependencies of `display_name` alone. This caused the ORM cache to be filled with many unnecessary stored fields for every record in the prefetch set. --- ### Dataset Volume The performance metrics were captured using a dataset consisting of: * **455,694** Journal Items (`account.move.line`) * **19,947** Journal Entries (`account.move`) --- ### Solution Add a single `fetch(['display_name'])` call on the browsed recordset. By calling `fetch(['display_name'])` upfront, the ORM goes through `_determine_fields_to_fetch(['display_name'])`, which walks only the declared `field_depends` of `display_name` and fetches **only those specific stored fields**. nothing more. --- ### Impact & Results | Metric | Before Optimization | After Optimization | Change / Note | | :--- | :--- | :--- | :--- | | **Peak Memory** | ~856 MB | ~223 MB | ~74% reduction | | **Execution Time** | 2.48s | 2.13s | About the same time with multiple tries | OPW-6275158 Forward-Port-Of: odoo/enterprise#121020
This update clarifies the Budget Report by adding more specific labels for budget lines. Previously, lines were grouped with generic names like 'Budget 2026 x', making it difficult to distinguish them. Now, the report includes the associated analytic accounts, providing a clearer and more informative view of budget data.
Original PR description
Budget report grouping by budget line displayed the budget name for every line, which made different lines indistinguishable and produced labels like "Budget 2026 x", "Budget 2026 x (2)", etc. Compute a more specific display name for budget lines by appending the analytic accounts concerned by the line to the budget name. Also expose Budget Line as a first-class group-by in the Budget Report search view and apply it by default when opening the report. task-6293065
This update resolves an issue where clicking the 'Documents' button on an employee form opened a new browser tab. The change adds a setting to ensure the button opens directly within the existing employee form, improving user experience and workflow efficiency.
Original PR description
Issue: ---------------------------------------- When on an employee form, clicking the "Documents" button opens a new page instead of staying on the same. Steps to reproduce: ---------------------------------------- - Install `documents_hr` - Go on an employee form - Click the "Documents" button - It opens a new page Cause: ---------------------------------------- The `'ir.actions.act_url'` opens a new page by default. Solution: ---------------------------------------- Add `'target': 'self',` to make it open the URL in the same page. opw-6284677
7 changes
Resolved issues and error corrections
This update ensures that partner data imported into the POS system from the DIAN tax authority is correctly synchronized after a refresh. Previously, the system didn't immediately update the POS with the latest information, leading to potential inaccuracies. This fix resolves this issue by ensuring data consistency.
Original PR description
Step to reproduce: - install l10n_co_dian and pos - open pos and click on create a new partner from partner list - enter name ex. "temp", identification number, click on form - notice a `refresh…
Step to reproduce: - install l10n_co_dian and pos - open pos and click on create a new partner from partner list - enter name ex. "temp", identification number, click on form - notice a `refresh icon` is visible: click on it. Observation: - the dialog is closed and partner is selected with "temp" name Expected: - with valid government credentials and a valid identification number, the refresh action should also update the partner data on the POS side Cause: - the refresh button triggers the `button_l10n_co_dian_refresh_data` action, which fetches the legal name and email from the government service - although the backend record is correctly updated, the new values are not immediately synchronized with the POS - when the refresh button is clicked, editPartner() first triggers `web_save` using the temporary "temp" name and immediately reads the partner data afterward - the refresh action executes later and updates the contact with the fetched legal information, but the POS is not aware of these subsequent changes Fix: - read the data again if there is any update caused by this action. - this is done by overriding `afterExecuteActionButton` of FormController class opw-6198035
This update fixes an issue where bank verification timestamps were incorrectly interpreted, leading to display errors for users in Poland. The change converts timestamps from the local Polish timezone to UTC, ensuring accurate display and preventing timezone-related problems with the government API.
Original PR description
The gov API returns a 'requestDateTime' in str format in PL timezone. This commit converts it back to UTC timezone for a better display in payment form. fields.Datetime assume the value is in UTC time and so when a field of this type is displayed, it's converted to the user timezone. This cause issue with the PL API call because the API will send us 9:25 PL TZ but if we store it directly, it will be interpreted by the ORM as 9:25 UTC and displayed to the user that's in UTC+2 as 11:25 task-6314380
This update resolves an issue where users with sales permissions couldn't modify production orders linked to sales documents. The fix adjusts security rules to grant necessary access, allowing sales users to correctly manage their own production orders within the system. This ensures consistent workflow and avoids operational bottlenecks.
Original PR description
### Steps to reproduce: - Ensure `sale_stock_renting` is installed - Enable Multi-Steps Routes > Unarchive MTO - Create a product P with a BoM and the routes MTO + manufacture - Create anc confirm a…
### Steps to reproduce: - Ensure `sale_stock_renting` is installed - Enable Multi-Steps Routes > Unarchive MTO - Create a product P with a BoM and the routes MTO + manufacture - Create anc confirm a sale order for A unit of P - Log in with an other user with with mrp User rights and sales User: Own Documents Only (he should not have access to the SO) - Open the MO, add a component line and save #### > Access Error: Blame the following rule: - Personal Order ### Cause of the issue: Writing on the `move_raw_ids` will trigger a call of the `_autoconfirm_production` in order to confirm the newly created move: https://github.com/odoo/odoo/blob/e447f4849056a0aab35966fb6ba595ebaadb79ab/addons/mrp/models/mrp_production.py#L990-L991 https://github.com/odoo/odoo/blob/e447f4849056a0aab35966fb6ba595ebaadb79ab/addons/mrp/models/mrp_production.py#L1422-L1423 During this confirmation process, one calls the `_merge_moves` method in order to merge this new move (if relevant) to any already existing one. https://github.com/odoo/odoo/blob/e447f4849056a0aab35966fb6ba595ebaadb79ab/addons/stock/models/stock_move.py#L1575-L1576 Now, the issue is that, `sale_stock_renting` modeule overrides the method `_prepare_merge_moves_distinct_fields` determining the fields relevant to the merge by requiring a read access to the `is_rental_order` compute field of the `sale_order` linked to the MO: https://github.com/odoo/enterprise/blob/b66097122ba3a758734ac6fb2b26579c35cb72c2/sale_stock_renting/models/stock_move.py#L34-L40 However, due to the 'Personal Orders' ir.rule, the user does not have a read access to this record: https://github.com/odoo/odoo/blob/e447f4849056a0aab35966fb6ba595ebaadb79ab/addons/sale/security/ir_rules.xml#L44-L49 Enterprise: https://github.com/odoo/enterprise/pull/121135 opw-6275658 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fix resolves an issue where users with specific access rights were prevented from adding components to rental orders. The update adjusts security rules to allow these users to modify the order, ensuring proper functionality for rental order management within the production environment.
Original PR description
### Steps to reproduce: - Ensure `sale_stock_renting` is installed - Enable Multi-Steps Routes > Unarchive MTO - Create a product P with a BoM and the routes MTO + manufacture - Create anc confirm a…
### Steps to reproduce: - Ensure `sale_stock_renting` is installed - Enable Multi-Steps Routes > Unarchive MTO - Create a product P with a BoM and the routes MTO + manufacture - Create anc confirm a sale order for A unit of P - Log in with an other user with with mrp User rights and sales User: Own Documents Only (he should not have access to the SO) - Open the MO, add a component line and save #### > Access Error: Blame the following rule: - Personal Order ### Cause of the issue: Writing on the `move_raw_ids` will trigger a call of the `_autoconfirm_production` in order to confirm the newly created move: https://github.com/odoo/odoo/blob/e447f4849056a0aab35966fb6ba595ebaadb79ab/addons/mrp/models/mrp_production.py#L990-L991 https://github.com/odoo/odoo/blob/e447f4849056a0aab35966fb6ba595ebaadb79ab/addons/mrp/models/mrp_production.py#L1422-L1423 During this confirmation process, one calls the `_merge_moves` method in order to merge this new move (if relevant) to any already existing one. https://github.com/odoo/odoo/blob/e447f4849056a0aab35966fb6ba595ebaadb79ab/addons/stock/models/stock_move.py#L1575-L1576 Now, the issue is that, `sale_stock_renting` module overrides the method `_prepare_merge_moves_distinct_fields` determining the fields relevant to the merge by requiring a read access to the `is_rental_order` compute field of the `sale_order` linked to the MO: https://github.com/odoo/enterprise/blob/b66097122ba3a758734ac6fb2b26579c35cb72c2/sale_stock_renting/models/stock_move.py#L34-L40 However, due to the 'Personal Orders' ir.rule, the user does not have a read access to this record: https://github.com/odoo/odoo/blob/e447f4849056a0aab35966fb6ba595ebaadb79ab/addons/sale/security/ir_rules.xml#L44-L49 Community: https://github.com/odoo/odoo/pull/271017 opw-6275658
This update resolves a technical issue in the POS system where a traceback error occurred when users initiated a 'Force Cancel' after a Pine Labs payment was cancelled. The fix ensures the system correctly handles payment line status transitions, preventing errors and improving the user experience during payment cancellation.
Original PR description
**Step to Reproduce:** 1. Open the POS. 2. Add any product to the order. 3. Proceed to the payment screen and select `Pine Labs` as the payment method. 4. Observe that the Pine Labs terminal does not…
**Step to Reproduce:** 1. Open the POS. 2. Add any product to the order. 3. Proceed to the payment screen and select `Pine Labs` as the payment method. 4. Observe that the Pine Labs terminal does not respond and no payment popup appears on the device. 5. Wait until the payment request is cancelled (either manually or due to timeout). 6. Click the `Force Cancel` button. 7. Observe that the POS throws a traceback. **Video:** https://drive.google.com/file/d/1A3QPdby-J12IWgOX_SfCLrauQ_QnbqvG/view **Issue:** When a Pine Labs payment request is cancelled (either through a cancel request or by timeout), clicking the `Force Cancel` button results in a traceback in the POS. **Reason:** During the cancellation flow, the payment line status is updated to `retry` so that the transaction can be marked as cancelled and retried if necessary. Later, when the user clicks `Force Cancel`, `_paymentCancelRequestHandler()` attempts to retrieve the pending Pine Labs payment line using: ```javascript const line = this.pendingPineLabsPaymentLine(); ``` However, `pendingPineLabsPaymentLine()` only returns payment lines whose status is not `retry`, as defined here: https://github.com/odoo/odoo/blob/19.0/addons/point_of_sale/static/src/app/services/pos_store.js#L1820 Since the payment line was already transitioned to the `retry` state during the cancellation flow, no `payment line` is found and `line` becomes `undefined`. The handler subsequently attempts to update the status of this `undefined` `payment line`, resulting in the traceback when `Force Cancel` is executed. **Solution:** Add a condition in `_paymentCancelRequestHandler()` to verify that a payment line is available before attempting to update its status. If no payment line is found, it indicates that the payment line has already been moved to the `retry` state during a previous cancellation attempt. In such cases we clear `pollingTimeout`, `inactivityTimeout` and reset `this.payment_stopped` to `false`. This prevents the traceback while ensuring that the `Force Cancel` flow properly cleans up the pending payment state. opw-6297135
This update fixes an issue where a product's serial number was incorrectly displayed twice after a page refresh in the Point of Sale (PoS) system. The root cause was a temporary lot number lingering in the system's database, leading to duplication. This change ensures accurate serial number display and a consistent user experience.
Original PR description
Steps to reproduce ------------------ 1. Have a product tracked by serial number, with stock to sell. 2. In PoS, sell one unit, set a serial number, and validate. 3. Refresh the page, then open the order again. -> the serial number is shown twice (after a second refresh it goes back to one). Why the issue ------------- When the order is synced, the server returns the real lot and it replaces the temporary one on the line. The temporary lot is not used anymore, but it stays in IndexedDB and still points to the line. So on the next reload it is loaded back, linked again to the line, and we get two lots on the same line. The fix ------- A lot that is not linked to any order line anymore is now considered removable, so it is not kept in IndexedDB and cannot be re-added on the next reload. opw-6092527
This update fixes an issue where customer names weren't correctly displayed in Odoo bookings created through Reserve with Google. Now, when booking through Google, the customer's full name (first and last) is used instead of just their email address, improving the user experience and data accuracy. This ensures booking details match the customer's actual identity.
Original PR description
When a customer books through Reserve with Google, the createBooking payload carries the booker given_name and family_name next to the email, but the handler passed only the normalized email to…
When a customer books through Reserve with Google, the createBooking payload carries the booker given_name and family_name next to the email, but the handler passed only the normalized email to _mail_find_partner_from_emails. The new res.partner was therefore created with its name falling back to the email, see https://github.com/odoo/odoo/blob/aa7b5921191a0ff53ef1cc32af99fe458c45c0da/addons/mail/models/res_partner.py#L177 That name then flows into the calendar.event name, the attendee common_name and the contact details, all showing the email instead of the customer name. The module has read neither field since it was added in https://github.com/odoo/enterprise/commit/2e855b910173b56e8501d0ebe9ee6f83ac5845bc. Build the booker name from given_name and family_name and pass it with the email through formataddr in google_reserve_booking_create, so a newly created partner is named after the customer. A partner matched on an existing email keeps its current name. Steps to reproduce: 1. Enable Reserve with Google on an appointment type. 2. Book a slot from Google Maps with given name John and family name Doe. 3. Open the created booking and its contact in Odoo. => the contact name is the email instead of John Doe Ticket [link](https://www.odoo.com/odoo/project/49/tasks/6232318) opw-6232318
4 changes
Resolved issues and error corrections
This update resolves a test failure related to database constraint violations (specifically `RESTRICT_VIOLATION`) when using PostgreSQL 18. The change involves updating a test to handle errors more generically, ensuring the email alias functionality continues to work correctly. This is a routine maintenance fix.
Original PR description
This commit is kind of a follow up of
odoo/odoo@39cd4ea856fe00f5674f8c44b2b66cbf2705426d (in 18.0).
In a nutshell, following a standard-compliance fix (postgres/postgres@086c84b) has led to `RESTRICT_VIOLATION` being emitted in cases which formerly emitted `FOREIGN_KEY_VIOLATION`. One such case is specifically being tested for by `test_alias_domain_setup`, leading to this test failing systematically when running pg18:
psycopg2.errors.RestrictViolation: update or delete on table "mail_alias_domain" violates RESTRICT setting of foreign key constraint "mail_alias_alias_domain_id_fkey" on table "mail_alias"
DETAIL: Key (id)=(191) is referenced from table "mail_alias".
This commit updates the test to use the more generic `IntegrityError` as it's probably more than sufficient for our purposes.This update fixes an error in the German (skr03) accounting template. The incorrect account codes for cash discounts have been replaced with the correct ones, ensuring accurate financial reporting for German businesses using Odoo. This ensures compliance with German tax regulations.
Original PR description
The default cash discout accounts referenced in the
German skr03 template used the wrong account codes.
The template has been updated with the right ones.
task-4915939
opw-4909059
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prThis update fixes an error in the German (skr03) template for financial reports. The incorrect account codes for cash discounts have been corrected, ensuring accurate reporting for German businesses using this template. This ensures compliance and reliable financial data.
Original PR description
The default cash discount accounts referenced in the German skr03 template used the wrong account codes. The template has been updated with the right ones. task-4915939 opw-4909059
This update corrects a missing valid NUIT number in the MZ demo company setup. The change ensures the demo company accurately reflects MZ tax regulations, preventing potential errors during testing and demonstration. This fix resolves a Runbot error related to data validation.
Original PR description
Newer versions of stdnum (2.2) also test the number for MZ We did not have a valid NUIT number in the MZ demo company. Runbot error: https://runbot.odoo.com/runbot/build/114118067 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