Tuesday, August 18, 2026
36 changes · saas-19.4
Enhancements to existing features
The employee Gantt view in Manufacturing Work Orders now shows the progress bar again. This helps teams quickly see work progress in the schedule, improving visibility for planning and follow-up.
Original PR description
Since 19.4 the progress bar has been hidden for employee gantt. This commit makes sure it is visible. task-6459190
Doing an euclidean division on floats with the native operators is unreliable: because of IEEE-754 representation errors, `value1 % value2` can return a spurious remainder (e.g. `50.4 % 16.8 == 16.799999999999997` instead of 0.0) and `int(value1 / value2)` can truncate the quotient one step too low (e.g. `int(0.3 / 0.1) == 2` instead of 3). `float_div` returns the `(quotient, remainder)` pair free of those errors. The key is to never run a lossy `%` or `//` on the raw floats. Instead both ope
Original PR description
Doing an euclidean division on floats with the native operators is unreliable: because of IEEE-754 representation errors, `value1 % value2` can return a spurious remainder (e.g. `50.4 % 16.8 ==…
Doing an euclidean division on floats with the native operators is unreliable: because of IEEE-754 representation errors, `value1 % value2` can return a spurious remainder (e.g. `50.4 % 16.8 == 16.799999999999997` instead of 0.0) and `int(value1 / value2)` can truncate the quotient one step too low (e.g. `int(0.3 / 0.1) == 2` instead of 3). `float_div` returns the `(quotient, remainder)` pair free of those errors. The key is to never run a lossy `%` or `//` on the raw floats. Instead both operands are first snapped onto the precision grid with `float_round` and then scaled to integers: since a grid-snapped value is a multiple of `rounding`, dividing it by `rounding` counts how many grid steps it spans. That division is still noisy (`4.35 / 0.05 == 86.99999999999999`), so the result is passed through `builtins.round` to coerce it to the exact integer step count. The euclidean division itself is then a plain integer `divmod`, which is exact, and the remainder is scaled back to real units. This is why the correction is applied to the inputs and not to the output: rounding the result of a native `%` would only round an already-corrupt value, and would still misreport the quotient in the corner cases the util exists to handle. Dividing by `rounding` is meaningful for any precision, not only powers of ten: the grid step can be `0.05`, `0.25`, `0.5`, `0.03`, ... and `value / step` counts the steps in every case. This mirrors the normalize/denormalize scheme `float_round` already uses internally. The util shares `float_round`'s inherent limitation: the scaled step count must stay representable as an exact `float` integer, so exactness is lost past ~2**53 grid steps (extreme magnitudes at a fine precision). This is the IEEE-754 double-precision ceiling and is well outside any realistic quantity or price range. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281058 Forward-Port-Of: odoo/odoo#277160
Bulgaria made it mandatory for large companies to present a monthly file to report their VAT to the administration. To streamline that process, when the VAT return is validated and PDF is added to the attachments, the monthly General Ledger SAF-T file, the POKUPKI Purchase Report and PRODAGBI Sale Report are produced and added as well. Simplify the report file download error wizard's visuals and descriptions to improve readability. task-6007963 --- I confirm I have signed the CLA an
Original PR description
Bulgaria made it mandatory for large companies to present a monthly file to report their VAT to the administration. To streamline that process, when the VAT return is validated and PDF is added to the attachments, the monthly General Ledger SAF-T file, the POKUPKI Purchase Report and PRODAGBI Sale Report are produced and added as well. Simplify the report file download error wizard's visuals and descriptions to improve readability. task-6007963 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#269132
this commit move the save order button next to the action button. task-id: 6275576 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#268215
Original PR description
this commit move the save order button next to the action button. task-id: 6275576 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#268215
Release notes: ttps://github.com/odoo/owl/releases/tag/v3.0.0-alpha.46 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
Original PR description
Release notes: ttps://github.com/odoo/owl/releases/tag/v3.0.0-alpha.46 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
Resolved issues and error corrections
The timesheet assistant now handles timesheet data more reliably when entries are removed or were created elsewhere. This helps prevent errors and avoids unintended changes to previously processed assistant events.
Original PR description
## [FIX] timesheet_grid: avoid altering consumedEvents Before this commit, the objects inside consumedEvents attribute are altered because we keep the reference of those objects. This commit avoid altering the consumed events. ## [FIX] timesheet_grid: use recordsByStart instead of records Forward-Port-Of: odoo/enterprise#127698
Miscellaneous changes
The product specifications table is displayed whenever the product has tags, even if none of them are visible on the ecommerce website. The product tags template filters out non-visible tags, but the surrounding table remains rendered and appears empty. Only display the tags table when at least one tag is visible on ecommerce. @Tecnativa TT63855 **Description of the issue/feature this PR addresses:** The condition used to display the product tags table considers all tags associate
Original PR description
The product specifications table is displayed whenever the product has tags, even if none of them are visible on the ecommerce website. The product tags template filters out non-visible tags, but the…
The product specifications table is displayed whenever the product has tags, even if none of them are visible on the ecommerce website. The product tags template filters out non-visible tags, but the surrounding table remains rendered and appears empty. Only display the tags table when at least one tag is visible on ecommerce. @Tecnativa TT63855 **Description of the issue/feature this PR addresses:** The condition used to display the product tags table considers all tags associated with the product, including those that are not visible on ecommerce. **Current behavior before PR:** When a product only has non-visible tags, the tags table is displayed without any content. <img width="669" height="350" alt="image" src="https://github.com/user-attachments/assets/4758ea76-5186-4035-a065-aa4c71ce7053" /> **Desired behavior after PR is merged:** The tags table is only displayed when the product has at least one tag visible on ecommerce. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282348 Forward-Port-Of: odoo/odoo#278604
An internal accounting test was adjusted to match a related platform fix in grouped data reading. This helps keep automated checks reliable without changing day-to-day user workflows.
Original PR description
The fix at https://github.com/odoo/odoo/pull/281911 adds bin_size: tru in the web_read_group. This commit adpats an accounting test as a consequence Forward-Port-Of: odoo/enterprise#127994 Forward-Port-Of: odoo/enterprise#127638
The IoT device list now keeps pagination working when users open a device record. This prevents navigation issues in larger device lists and makes managing IoT devices smoother.
Original PR description
Since #72351, the pagination on IoT devices was broken due to how we were getting to the full device form when clicking on a record. We now change the override to use the existing method from the framework `switchToForm` which handles it better. opw-6058532 Forward-Port-Of: odoo/enterprise#127215 Forward-Port-Of: odoo/enterprise#126486
The Timesheet Assistant now combines selected suggestions that share the same rule template into one more natural description. This avoids repetitive text separated by semicolons, making generated timesheet entries easier to read and understand.
Original PR description
In this task, we improved the Timesheet Assistant by merging descriptions generated from the same rule templates. When multiple suggestions are selected that use the same rule template, the assistant now combines them into a single timesheet description instead of joining with ';' Example: Rule template: `Discussing with $1` Before: Discussing with A; Discussing with B After: Discussing with A and B Task-6348575 Forward-Port-Of: odoo/enterprise#127109 Forward-Port-Of: odoo/enterprise#126157
Restaurant preparation display cards now show the assigned course name, such as “Main Course,” instead of only a course number when course allocation is enabled. This makes kitchen preparation screens clearer and reduces confusion for staff handling multi-course orders.
Original PR description
Before this commit: ====================== Prep cards showed the course index, like T1 - C2, even when course allocation was enabled. After this commit: ==================== Prep cards show the allocated course name, like T1 - Main Course, when course allocation is enabled. Task-6421309
The call debrief timeline now keeps transcript markers aligned with the timeline direction in right-to-left language settings. This provides a more consistent and understandable call review experience for users working in languages such as Arabic or Hebrew.
Original PR description
The call debrief timeline was not properly adapted for RTL layouts. In Community, the timeline is forced to always render in LTR, as it represents the physical progression of time moving forward. To ensure consistency, this commit makes transcript markers within the timeline always render in LTR as well. task-6445011 Requires: - https://github.com/odoo/odoo/pull/280218
Creating appraisal goal templates no longer assigns them to a specific employee by default. This ensures templates created from the library or saved from an employee goal remain visible and reusable in the template list.
Original PR description
Steps to reproduce: - Go to Appraisals > Configuration > Goals > Library and create a goal template. - Or open an employee goal and click "Save as Template". - The created goal template is not visible in the goal template list view. Reason: An employee was set by default on new goal templates upon creation. Solution: Do not assign a default employee when creating a goal template. Task-6443339
The vehicle salary tab now shows the Benefit In Kind amount with the correct yearly label and keeps the label aligned next to the value. This avoids confusion when reviewing vehicle-related salary costs, with no changes to calculations or stored data.
Original PR description
The Benefit In Kind (BIK) amount on the vehicle model salary tab was labelled "/ month" while the underlying value is yearly, mismatching the other fields (CO2 fee, Cost, Total Cost) correctly suffixed. The unit label div was also missing the o_hr_narrow_field class used everywhere else in the module, so the unit label stretched to the far right of the row instead of sitting next to the value. Purely visual fix, no behavior or data change. task-6428222
The Timesheet Assistant now identifies time spent in spreadsheets as spreadsheet work instead of grouping it under Documents. This gives users more accurate timesheet suggestions and reduces manual corrections.
Original PR description
## Behavior Before the Commit When a user spent time working in a spreadsheet, the Timesheet Assistant grouped this time under "Working in Documents". This occurred because "Spreadsheet" is a module rather than an application, and the Assistant only creates suggestions for applications. As a result, it attempted to fall back to an application and frequently defaulted to the "Documents" application. ## New Expected Behavior After this Commit: When a user spends time in a spreadsheet, the Timesheet Assistant now generates a "Working in Spreadsheet" suggestion. This is enabled by a dedicated list of non‑application modules that allows specific modules to be recognized even when they are not applications. task-[6438536](https://www.odoo.com/odoo/project/4105/tasks/6438536) Forward-Port-Of: odoo/enterprise#126390
The scheduled cleanup for AI embeddings now correctly detects records created with deprecated embedding models. This helps ensure outdated AI data is refreshed as intended, reducing maintenance issues without changing the user workflow.
Original PR description
The embedding model deprecation cron starts by searching for chunks that are embedded using a model that hasn't been deprecated. However, due to an optimization in the ORM (optimize_type_selection),…
The embedding model deprecation cron starts by searching for chunks that are embedded using a model that hasn't been deprecated. However, due to an optimization in the ORM (optimize_type_selection), the search doesn't return any result. A domain that uses the 'not in' operator is converted by the optimization to use the 'in' operator and the values are replaced by the difference between the available selection values (self._selection) and the values in the domain. So, given that the selection values of the embedding_model field are the non deprecated embedding models and the search domain of the cron is ['embedding_model', 'not in', non deprecated embedding models] , the final domain will be ['embedding_model', 'in', non deprecated models list - non deprecated models list] = ['embedding_model', 'in', []] which will retrieve nothing from the DB because all records have an embedding_model. The main issue is that the optimization assumes that the available selection values are static. However, an old embedding model can be deprecated and a new one added which makes the optimization fail. So, the selection values are changed to be computed dynamically which will be skipped by the optimization.
Currently, trying to create a link via typing a url throws traceback in Safari. This happens because after merging commit [1], `addStep` is called in `onBeforeInputPrepareConvertToLink` but from saas-19.4 `addStep` function is replaced by `commit`. This PR aims to replace `addStep` to `commit` to prevent traceback. [1]: https://github.com/odoo/odoo/commit/e5af0308b3fb87abb04de07c8554658e892ee03e --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/subm
Original PR description
Currently, trying to create a link via typing a url throws traceback in Safari. This happens because after merging commit [1], `addStep` is called in `onBeforeInputPrepareConvertToLink` but from saas-19.4 `addStep` function is replaced by `commit`. This PR aims to replace `addStep` to `commit` to prevent traceback. [1]: https://github.com/odoo/odoo/commit/e5af0308b3fb87abb04de07c8554658e892ee03e --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
On a database that was not created with demo data, registering for Peppol using the "Odoo Demo ID" identification fails instead of activating the local demo/training registration. The registration wizard correctly shows "Demo" as the EDI mode once that identifier is selected, but submitting the registration still reaches out to the real Peppol Access Point, which the wizard cannot connect to, so the registration is blocked. Steps to reproduce: ------------------- * Create a new database wit
Original PR description
On a database that was not created with demo data, registering for Peppol using the "Odoo Demo ID" identification fails instead of activating the local demo/training registration. The registration…
On a database that was not created with demo data, registering for Peppol using the "Odoo Demo ID" identification fails instead of activating the local demo/training registration. The registration wizard correctly shows "Demo" as the EDI mode once that identifier is selected, but submitting the registration still reaches out to the real Peppol Access Point, which the wizard cannot connect to, so the registration is blocked. Steps to reproduce: ------------------- * Create a new database without demo data (e.g. a regular Odoo Online database, not a /trial one) * Install Accounting, open the Peppol registration wizard * Select "Odoo Demo ID" as the Electronic Address Scheme and fill in the other required fields * Click on Register > Observation: The wizard displays "Demo" as the EDI mode, yet registering raises "Failed to connect to Odoo Peppol Proxy." Manually creating the system parameter `account_peppol.edi.mode` with the value "demo" makes the registration succeed, but that parameter is only ever set automatically when the module's demo data is loaded. Why the fix: ------------ The wizard's displayed `edi_mode` correctly resolves to "demo" for the Odoo Demo ID EAS, but `handle_demo` - which decides whether `_can_connect`/`_create_connection` run against the local mock or the real Peppol proxy - recomputed the mode itself without passing that EAS along, so it could only detect demo mode via the system parameter or an already existing proxy user. Made `handle_demo` pass the record's own `peppol_eas` as `temporary_eas`, aligning its detection with what the wizard already displays. opw-6448276
Before this commit and since the new read_group (which fetches records from open groups server side), images were loaded as base64, overloading the return payload and potentially triggering overload errors (MemoryError) This was because the bin_size = true context key was forgotten. After this commit, images are not loaded as base64 thanks to that context key Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged:
Original PR description
Before this commit and since the new read_group (which fetches records from open groups server side), images were loaded as base64, overloading the return payload and potentially triggering overload errors (MemoryError) This was because the bin_size = true context key was forgotten. After this commit, images are not loaded as base64 thanks to that context key Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282562 Forward-Port-Of: odoo/odoo#281911
Before this commit, deleting a record leaves its id in the relations of a record deleted before it in the same update, and reading one of those relations hands out an entry for a record that is gone. This happens because an update takes a deleted record out of the relations that hold it, but forgets it as soon as it is deleted. However, deleting a record is what queues the deletion of the records it holds: `channelMembers` carries `onDelete: (r) => r.delete()`, so the members of a thread are
Original PR description
Before this commit, deleting a record leaves its id in the relations of a record deleted before it in the same update, and reading one of those relations hands out an entry for a record that is gone. This happens because an update takes a deleted record out of the relations that hold it, but forgets it as soon as it is deleted. However, deleting a record is what queues the deletion of the records it holds: `channelMembers` carries `onDelete: (r) => r.delete()`, so the members of a thread are deleted once the thread is already forgotten, and their ids stay in its `onlineMembers`. This commit fixes the issue by keeping the records deleted by an update known until it ends. Forward-Port-Of: odoo/odoo#282621 Forward-Port-Of: odoo/odoo#281983
**Problem**: When creating a percentage down payment with a Brazilian tax, the divide by zero error occurs because the factor contains a zero value. **Steps to reproduce**: 1. Set up Brazil localization with ```l10n_br_avatax```, ```l10n_br_edi```. 2. Create a service product with ```LC116``` code set up. 3. Create a sales order with the customer has ```Automatic Tax Mapping (Avalara Brazil)``` in their Fiscal Position. 4. Add the service product to the sales order and confirm it. 5. Cr
Original PR description
**Problem**: When creating a percentage down payment with a Brazilian tax, the divide by zero error occurs because the factor contains a zero value. **Steps to reproduce**: 1. Set up Brazil localization with ```l10n_br_avatax```, ```l10n_br_edi```. 2. Create a service product with ```LC116``` code set up. 3. Create a sales order with the customer has ```Automatic Tax Mapping (Avalara Brazil)``` in their Fiscal Position. 4. Add the service product to the sales order and confirm it. 5. Create a percentage down payment for the sales order. 6. Divide by zero error occurs. **Fix**: Check if the ```sum_of_factors``` is zero and if so, set the ```delta_factor``` to zero. before ```normalize_results['plus_sum_of_factors'] / normalize_results['sum_of_factors']``` opw-6446986 Forward-Port-Of: odoo/odoo#281571
Steps to reproduce: - Make sure you have 2 or more languages installed - Install events and website app - For the website, apply the languages you have in settings - Make sure website default language is different from backend language - Create an event - Go to the event's website page through the smart button - Switch the language of the frontend to one that is different from backend - Translate (alter) the description for this language - Click on the outlook icon to download the ics
Original PR description
Steps to reproduce: - Make sure you have 2 or more languages installed - Install events and website app - For the website, apply the languages you have in settings - Make sure website default…
Steps to reproduce: - Make sure you have 2 or more languages installed - Install events and website app - For the website, apply the languages you have in settings - Make sure website default language is different from backend language - Create an event - Go to the event's website page through the smart button - Switch the language of the frontend to one that is different from backend - Translate (alter) the description for this language - Click on the outlook icon to download the ics Current Behavior: The ics will contain a description based on the backend's chosen language Expected Behavior: The ics will contain a description based on the website's chosen language. If there's no website, it will use the browser's language Clarification: The current behavior is confusing for users as they will expect the ics to match the description of the current webpage which is dependent on the frontend's selected language. This current behavior also contradicts the google calendar behavior which grabs the description based on the frontend's selected language. The endpoints for retrieving the ics file now utilize the website=True flag to take advantage of IrHttp._match which will automatically set the context language to be the frontend's rather than the backend language. We want the ics file to be in the frontend language for visual consistency. Also, send_email_reminder function does not require with context for this reason opw-6235320 Forward-Port-Of: odoo/odoo#280520 Forward-Port-Of: odoo/odoo#271968
**Steps to reproduce** - Open any MO - Click on 'catalog' - Click on the three dots button of any product - Try to edit -> Traceback: `"product.product"."state" field is undefined.` **Cause** The `move_raw_ids` field on the MO form sets a context with `form_view_ref: 'mrp.view_mrp_stock_move_operations'`, so that editing a component's `stock.move` line in place opens that dedicated view: https://github.com/odoo/odoo/blob/20db2910d16fa6ebd07794fb9ed3fb1c8f57b0fc/addons/mrp/views/mrp_prod
Original PR description
**Steps to reproduce** - Open any MO - Click on 'catalog' - Click on the three dots button of any product - Try to edit -> Traceback: `"product.product"."state" field is undefined.` **Cause** The…
**Steps to reproduce** - Open any MO - Click on 'catalog' - Click on the three dots button of any product - Try to edit -> Traceback: `"product.product"."state" field is undefined.` **Cause** The `move_raw_ids` field on the MO form sets a context with `form_view_ref: 'mrp.view_mrp_stock_move_operations'`, so that editing a component's `stock.move` line in place opens that dedicated view: https://github.com/odoo/odoo/blob/20db2910d16fa6ebd07794fb9ed3fb1c8f57b0fc/addons/mrp/views/mrp_production_views.xml#L411-L417 The 'Catalog' button lives inside that same field, and calls `action_add_from_catalog_raw`, which delegates to the mixin's `action_add_from_catalog`: https://github.com/odoo/odoo/blob/3dd41395e2e4205fa477eb474d4a4dba0a976154/addons/product/models/product_catalog_mixin.py#L17 Which conserve the `'form_view_ref'` from context: https://github.com/odoo/odoo/blob/3dd41395e2e4205fa477eb474d4a4dba0a976154/addons/product/models/product_catalog_mixin.py#L28 and that action requests its form view with `view_id=False`: https://github.com/odoo/odoo/blob/3dd41395e2e4205fa477eb474d4a4dba0a976154/addons/product/models/product_catalog_mixin.py#L25 Which will try to load `view_mrp_stock_move_operations`, since: https://github.com/odoo/odoo/blob/3dd41395e2e4205fa477eb474d4a4dba0a976154/odoo/addons/base/models/ir_ui_view.py#L3002-L3005 `_get_view` never checks that the resolved view's `model` matches the model it was asked for, so it returns `view_mrp_stock_move_operations`for the `product.product` model: https://github.com/odoo/odoo/blob/3dd41395e2e4205fa477eb474d4a4dba0a976154/addons/mrp/views/stock_move_views.xml#L41 https://github.com/odoo/odoo/blob/3dd41395e2e4205fa477eb474d4a4dba0a976154/addons/stock/views/stock_move_views.xml#L128 `state` doesn't exist on `product.product`, hence the crash. opw-6433620 Forward-Port-Of: odoo/odoo#279811
When using multiple devices sharing draft orders, a race condition can happen where one device reuses another device's empty synced draft order. This leads to duplicate UUIDs, which triggers automatic order merging in `sync_from_ui` on the server and clears the table association. To prevent this: - Filter out synced orders (`!order.isSynced`) in `getEmptyOrder()`, `createOrderIfNeeded()`, and `setTable()` when looking for reusable empty orders. - This ensures each terminal only reuses its o
Original PR description
When using multiple devices sharing draft orders, a race condition can happen where one device reuses another device's empty synced draft order. This leads to duplicate UUIDs, which triggers automatic order merging in `sync_from_ui` on the server and clears the table association. To prevent this: - Filter out synced orders (`!order.isSynced`) in `getEmptyOrder()`, `createOrderIfNeeded()`, and `setTable()` when looking for reusable empty orders. - This ensures each terminal only reuses its own locally created, unsynced empty orders, guaranteeing unique UUIDs per device session. task-id: 6296661 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#269551
`cbc:RoundingAmount` was the sum of `raw_total_excluded` over the non-fixed taxes plus the sum of `raw_tax_amount` over all the taxes, so the base of the line was counted once per non-fixed tax, inflating the line total. `cbc:TaxableAmount` was taken from the tax details of each grouping key, which is the base of that specific tax not the net amount of the line expected by JoFotara. Both amounts are now read from the base line tax details (`raw_total_included` and `raw_total_excluded`), so
Original PR description
`cbc:RoundingAmount` was the sum of `raw_total_excluded` over the non-fixed taxes plus the sum of `raw_tax_amount` over all the taxes, so the base of the line was counted once per non-fixed tax, inflating the line total. `cbc:TaxableAmount` was taken from the tax details of each grouping key, which is the base of that specific tax not the net amount of the line expected by JoFotara. Both amounts are now read from the base line tax details (`raw_total_included` and `raw_total_excluded`), so they describe the line itself regardless of the number of taxes set on it. The document level `cbc:TaxableAmount` keeps using the aggregated tax details. Even tho the problems were hidden because in Jordan, a line wouldn't have more than 1 percent tax + 1 fixed tax, it emerged during the development of the fix in this PR: https://github.com/odoo/odoo/pull/279335 Forward-Port-Of: odoo/odoo#281262
Fix for the runbot nightly error 944444. bug: The website configurator crashed entirely if one theme snippet's template was missing, instead of just skipping that snippet. steps: Only visible while running `test_01_configurator_translation` fix: Catch MissingError, alongside ValueError, when generating and rendering configurator snippet content. task-6325919
Original PR description
Fix for the runbot nightly error 944444. bug: The website configurator crashed entirely if one theme snippet's template was missing, instead of just skipping that snippet. steps: Only visible while running `test_01_configurator_translation` fix: Catch MissingError, alongside ValueError, when generating and rendering configurator snippet content. task-6325919
Prior to this commit, the call debrief timeline was not properly adapted for RTL layouts. The playhead and timestamp were positioned incorrectly, making the component unusable in RTL. This commit forces the timeline to always render in LTR, as it represents the physical progression of time moving forward. task-6445011 Requires: - https://github.com/odoo/enterprise/pull/127038 | Before | After | |--------|--------| | <img width="1920" height="698" alt="image" src="https://github.com/
Original PR description
Prior to this commit, the call debrief timeline was not properly adapted for RTL layouts. The playhead and timestamp were positioned incorrectly, making the component unusable in RTL. This commit…
Prior to this commit, the call debrief timeline was not properly adapted for RTL layouts. The playhead and timestamp were positioned incorrectly, making the component unusable in RTL. This commit forces the timeline to always render in LTR, as it represents the physical progression of time moving forward. task-6445011 Requires: - https://github.com/odoo/enterprise/pull/127038 | Before | After | |--------|--------| | <img width="1920" height="698" alt="image" src="https://github.com/user-attachments/assets/780f6e83-b67d-44bc-8b00-8e92048ff13b" /> | <img width="1390" height="463" alt="Screenshot 2026-08-11 at 08 51 00" src="https://github.com/user-attachments/assets/8a2a833c-2164-40ed-a4c7-006b7ca5bec4" /> | | <img width="1385" height="418" alt="Screenshot 2026-08-04 at 15 02 05" src="https://github.com/user-attachments/assets/f0c75f29-e459-4ee7-976d-3674ae76ff81" /> | <img width="1384" height="479" alt="Screenshot 2026-08-11 at 08 51 22" src="https://github.com/user-attachments/assets/f60b98c5-5a33-4d01-8521-0f2f3bdd6424" /> | --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Currently, with images enabled for quotation reports and if the product name is long enough, it overflows through the column border a bit before breaking to the next line. This seems to be caused by some incompatibility between wkhtmltopdf and d-flex, adding `col` to the product name container forces it to respect column boundaries. This commit also adds `text-break` as having a long uninterupded string in the description would end up stretching the column and making the next ones disapear
Original PR description
Currently, with images enabled for quotation reports and if the product name is long enough, it overflows through the column border a bit before breaking to the next line. This seems to be caused by…
Currently, with images enabled for quotation reports and if the product name is long enough, it overflows through the column border a bit before breaking to the next line. This seems to be caused by some incompatibility between wkhtmltopdf and d-flex, adding `col` to the product name container forces it to respect column boundaries. This commit also adds `text-break` as having a long uninterupded string in the description would end up stretching the column and making the next ones disapear. <img width="811" height="266" alt="image" src="https://github.com/user-attachments/assets/90043c88-d03f-4324-9935-e669f6a256ab" /> <img width="964" height="431" alt="image" src="https://github.com/user-attachments/assets/2b8e8a6c-6fd5-4813-8160-d94bbb5490d1" /> ### Steps to reproduce: - Enable Display Product Images in the setting - Create a product with an image - Create a quotation with said product and add a description that is long enough to break to the next line - Print said quotation - You will notice that before the line breaks it will overflow to the next column (you might need to tweak the description a bit by removing or adding a few lines) opw-6367076 Forward-Port-Of: odoo/odoo#275978
Improves UX by deselecting when clicking the header checkbox in list views instead of selecting all. WHY: Fits the UX of almost all other software and saves one click :) Since @34b9af762fa2, the header checkbox of a list view renders in its indeterminate state ([-]) when part of the displayed records are selected. When doing that feature, we thought about the "escape" case to deselect all, but not the click header checkbox case. This PR fixes that. task-6237965
Original PR description
Improves UX by deselecting when clicking the header checkbox in list views instead of selecting all. WHY: Fits the UX of almost all other software and saves one click :) Since @34b9af762fa2, the header checkbox of a list view renders in its indeterminate state ([-]) when part of the displayed records are selected. When doing that feature, we thought about the "escape" case to deselect all, but not the click header checkbox case. This PR fixes that. task-6237965
Clicking the internal-link arrow on `work_entry_type_id` (Time Off Type) implicitly saved the `hr.leave` record before opening the related form dialog, since `Many2One.openRecordInDialog()` calls `willOpenRecordInDialog()`, which defaults to `record.save()`. For a new leave request, this triggered `hr.leave.create()`'s validation logic, auto-confirming (or even auto-approving) the request before the user had finished the wizard. This premature save was also the root cause of two related bugs,
Original PR description
Clicking the internal-link arrow on `work_entry_type_id` (Time Off Type) implicitly saved the `hr.leave` record before opening the related form dialog, since `Many2One.openRecordInDialog()` calls…
Clicking the internal-link arrow on `work_entry_type_id` (Time Off Type) implicitly saved the `hr.leave` record before opening the related form dialog, since `Many2One.openRecordInDialog()` calls `willOpenRecordInDialog()`, which defaults to `record.save()`. For a new leave request, this triggered `hr.leave.create()`'s validation logic, auto-confirming (or even auto-approving) the request before the user had finished the wizard. This premature save was also the root cause of two related bugs, both fixed as a side effect: closing the Time Type dialog threw `TypeError: Cannot read properties of undefined (reading 'focus')` (the save re-rendered the parent, leaving `Many2One`'s `onClose` pointing at a stale component), and that crash aborted the promise chain before it could reload the calendar, leaving a newly-created leave request missing from view until a manual refresh. Adds a `many2one_no_save` field widget overriding `willOpenRecordInDialog` to skip the save, applied to `work_entry_type_id` on the base `hr_leave_view_form` so all inheriting views are covered. task-6452848
Currently, an error occurs when updating the quantity of an SOL in the portal. **Steps to Reproduce:** - Install the `sale_management` module. - Go to `Settings` and enable `Pricelists` under Pricing. - Go to `Sales` > `Orders` > `Orders` and create a `sale order`. - Add an `order line` of type `Section`, click the `three-dot` menu on the line, and click `Set Optional`. - Add another line using `Add a line` and enter only the `description` in that line. - Save the `order` and clic
Original PR description
Currently, an error occurs when updating the quantity of an SOL in the portal. **Steps to Reproduce:** - Install the `sale_management` module. - Go to `Settings` and enable `Pricelists` under…
Currently, an error occurs when updating the quantity of an SOL in the portal. **Steps to Reproduce:** - Install the `sale_management` module. - Go to `Settings` and enable `Pricelists` under Pricing. - Go to `Sales` > `Orders` > `Orders` and create a `sale order`. - Add an `order line` of type `Section`, click the `three-dot` menu on the line, and click `Set Optional`. - Add another line using `Add a line` and enter only the `description` in that line. - Save the `order` and click `Preview`. - `Increase` the quantity of the line using the + icon. `ValueError: Expected singleton: product.product()` After [recent commit], support for productless Sale Order Lines was added, allowing users to create quotation/invoice lines directly from descriptions without requiring a product. After [this commit], when updating the quantity of a productless SOL in the portal, the price is updated based on the pricelist [1]. While getting the pricelist price [2] for the SOL, the product is ensured on the SOL, which raises the error [3] because the SOL does not have a product. This commit ensures that the unit price is updated based on the pricelist only if the line contains a product. [recent commit]: https://github.com/odoo/odoo/commit/d069ce59e28fda2bc25fb89fd01ee7b988a30fa0 [this commit]: https://github.com/odoo/odoo/commit/86d40fe5c5ad32af0ceca7cd384b96a8a2f4adc3 [1]- https://github.com/odoo/odoo/blob/e940a655aba06adc784008b72a3917170fdb3dd0/addons/sale_management/controllers/portal.py#L68-L69 [2]- https://github.com/odoo/odoo/blob/e940a655aba06adc784008b72a3917170fdb3dd0/addons/sale/models/sale_order_line.py#L783 [3]- https://github.com/odoo/odoo/blob/e940a655aba06adc784008b72a3917170fdb3dd0/addons/sale/models/sale_order_line.py#L801 sentry-7665145989 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
***Steps to reproduce*:** * Install the `l10n_din5008` module. * Set up a German Company and set the fiscal location to Germany. * Select the German company and create a new Purchase Journal. * Enable **Self Billing** for the journal. * Create a vendor bill and print the PDF. ***Observed behavior*:** * The printed document displays the regular vendor bill header instead of the self-billing header. ***Cause*:** * The condition required to display the self-billing header was mi
Original PR description
***Steps to reproduce*:** * Install the `l10n_din5008` module. * Set up a German Company and set the fiscal location to Germany. * Select the German company and create a new Purchase Journal. * Enable **Self Billing** for the journal. * Create a vendor bill and print the PDF. ***Observed behavior*:** * The printed document displays the regular vendor bill header instead of the self-billing header. ***Cause*:** * The condition required to display the self-billing header was missing from the report template if self-billing is enabled. ***Fix*:** * Add the missing condition so that the self-billing header is displayed when **Self Billing** is enabled on the journal. * For reference, here is the [Document](https://www.gesetze-im-internet.de/ustg_1980/__14.html) link. Ticket [link](https://www.odoo.com/odoo/project.task/6281066) opw-6281066 Forward-Port-Of: odoo/odoo#282664 Forward-Port-Of: odoo/odoo#272857
## Description When a CI/NIE number fails the check digit validation, the raised error suggests `3:402.010-2 or 93:402.010-1 (CI or NIE)` as the expected format. This is misleading for two reasons: - The colon notation comes from Uruware's technical manual and is not how identity card numbers are written in Uruguay: users write `3.402.010-1` or plain digits (`34020101`). Real users facing the error keep reformatting a number whose check digit is simply wrong, believing the problem is the forma
Original PR description
## Description When a CI/NIE number fails the check digit validation, the raised error suggests `3:402.010-2 or 93:402.010-1 (CI or NIE)` as the expected format. This is misleading for two reasons: -…
## Description When a CI/NIE number fails the check digit validation, the raised error suggests `3:402.010-2 or 93:402.010-1 (CI or NIE)` as the expected format. This is misleading for two reasons: - The colon notation comes from Uruware's technical manual and is not how identity card numbers are written in Uruguay: users write `3.402.010-1` or plain digits (`34020101`). Real users facing the error keep reformatting a number whose check digit is simply wrong, believing the problem is the format. - The CI example shown is itself an **invalid** number: the check digit of `3.402.010` is `1`, not `2` — the module's own test suite (`l10n_uy/tests/test_check_vat.py`) uses `3:402.010-2` as an invalid sample. This was reported by an Uruguayan eCommerce user who lost sales because buyers interpreted the message as requiring an unusual format that does not exist in Uruguay. ## Change Replace the examples with valid numbers written in the notations actually used in Uruguay, and clarify that separators are optional — which is exactly what `_l10n_uy_ci_nie_is_valid()` already accepts (it strips `:. ,-` before checking the verification digit): ``` 3.402.010-1 or 34020101 (CI), 93.402.010-1 (NIE); dots and dash are optional ``` Only the `expected_format` string changes; the validation logic is untouched. Existing tests only assert the fixed part of the message (`The CI/NIE number.*does not seem to be valid`), so they are unaffected. Forward-Port-Of: odoo/odoo#282489
**Steps to reproduce:** 1. Install the sale module with demo data. 2. Open a sale order and add a combo product (e.g. "Office Combo"). 3. Note the displayed untaxed amount on the combo item lines (e.g. 160.00). 4. Switch the document tax mode from "Tax Excl." to "Tax Incl." using the toggle at the top of the Order Lines tab. **Issue:** - After switching to "Tax Incl." mode, the total on the sale order is higher than the previous untaxed amount (e.g. shows 266.00 instead of the 160.00).
Original PR description
**Steps to reproduce:** 1. Install the sale module with demo data. 2. Open a sale order and add a combo product (e.g. "Office Combo"). 3. Note the displayed untaxed amount on the combo item lines…
**Steps to reproduce:** 1. Install the sale module with demo data. 2. Open a sale order and add a combo product (e.g. "Office Combo"). 3. Note the displayed untaxed amount on the combo item lines (e.g. 160.00). 4. Switch the document tax mode from "Tax Excl." to "Tax Incl." using the toggle at the top of the Order Lines tab. **Issue:** - After switching to "Tax Incl." mode, the total on the sale order is higher than the previous untaxed amount (e.g. shows 266.00 instead of the 160.00). - The same switch works correctly on regular (non-combo) product lines **Expected behavior:** - the new total should equal the previous untaxed amount. **Why this happens:** - `_onchange_order_line` is triggered on every `order_line` change, including when switching `document_tax_mode` causes `price_subtotal` to update on existing lines. - The unconditional write to `product_uom_qty` and `discount` on all combo item lines was calling '_compute_price_unit` even when neither value had changed. - `_compute_price_unit` then called `_reset_price_unit` under the new `document_tax_mode`, which re-calculated the stored `price_unit` instead of leaving it untouched for `_compute_amount` to reinterpret correctly. **Fix:** - Only sync `product_uom_qty` and `discount` to the combo item lines whose current values actually differ from the parent line. When no value has changed, no write occurs, so `_compute_price_unit` is not called. opw-6427963
Steps: - Install l10n_ma module. - Go to Address page in portal. - Select Morocco country. - Set any random invalid value for ICE input. Issue: - It wont allow to save address and will not give any error or suggestion instead it raises validation error in logger. Cause: - Since recent [fix](https://github.com/odoo/odoo/pull/271969) invalid additional_identifier raises an error for invalid values and in portal we can't display those error directly. Fix: - Validate `additional_iden
Original PR description
Steps: - Install l10n_ma module. - Go to Address page in portal. - Select Morocco country. - Set any random invalid value for ICE input. Issue: - It wont allow to save address and will not give any error or suggestion instead it raises validation error in logger. Cause: - Since recent [fix](https://github.com/odoo/odoo/pull/271969) invalid additional_identifier raises an error for invalid values and in portal we can't display those error directly. Fix: - Validate `additional_identifier` in validate address values and and mark those identifier as invalid field for invalid values to give proper error message and not raise validation error. Also skip `_validate_identifier` for `no_vat_validation` context in creation since we already validate those identifier values.
Fix the function signature of the _reset_peppol_configuration function Step to reproduce: - Install l10n_fr_pdp and register a company on Peppol - When the _peppol_out_of_sync_disconnect_this_database will be called, it will call the _reset_peppol_configuration(soft=True), and since l10n_fr_pdp overrides this function but don't declare the soft parameter, it will raise a TypeError. opw-5728596 Forward-Port-Of: odoo/odoo#282763
Original PR description
Fix the function signature of the _reset_peppol_configuration function Step to reproduce: - Install l10n_fr_pdp and register a company on Peppol - When the _peppol_out_of_sync_disconnect_this_database will be called, it will call the _reset_peppol_configuration(soft=True), and since l10n_fr_pdp overrides this function but don't declare the soft parameter, it will raise a TypeError. opw-5728596 Forward-Port-Of: odoo/odoo#282763