Daily updates from Odoo
Wednesday, July 8, 2026
189 changes
21 changes
Enhancements to existing features
This update adds missing translations for customer- and staff-facing messages across Point of Sale modules. It makes dialogs, errors, alerts, and warnings easier to understand for users working in supported languages.
Original PR description
pos* = All POS module In this commit: -------------------------------- Add missing translations for user-visible strings across POS modules. - Translated dialogs, errors, alerts, and other UI-visible messages - Updated Python-side UserError, ValidationError, and warning messages Task-5406947 Related PR-https://github.com/odoo/odoo/pull/239972 Forward-Port-Of: odoo/enterprise#122511 Forward-Port-Of: odoo/enterprise#102094
The printer settings now only show the oBox IP field when it is relevant for ePOS printers. The interface also hides technical service details from the oBox view, making setup cleaner and easier for users.
Original PR description
This PR adapts the view to only allow the user to set obox ip if the type of printer used is epos as it doesnt matter otherwise It also hides the services installed on the obox as it's not useful for the user task-6330864
Resolved issues and error corrections
Odoo now saves the reply count returned by Twitter/X for social stream posts. This lets users see comment activity alongside other engagement metrics, giving a more complete view of post performance.
Original PR description
Twitter/X tweet metrics returned by the API include the number of replies in the `public_metrics.reply_count` field. This commit stores that value on social stream posts so the comments count can be displayed alongside other engagement metrics. API Documentation: https://docs.x.com/x-api/fundamentals/metrics#post-metrics Task-6251172 Forward-Port-Of: odoo/enterprise#120182
The task Gantt view now loads correctly when grouped by Sale Order Item. This prevents an error caused by an outdated hours field name, allowing teams to review project work and sales-linked tasks without interruption.
Original PR description
### Steps to reproduce - Install `sale_timesheet_enterprise`. - Go to **Tasks → All Tasks**. - Switch to the **Gantt** view. - Group by **Sale Order Item** (`sale_line_id`). ### Issue A traceback is…
### Steps to reproduce - Install `sale_timesheet_enterprise`. - Go to **Tasks → All Tasks**. - Switch to the **Gantt** view. - Group by **Sale Order Item** (`sale_line_id`). ### Issue A traceback is raised when loading the Gantt view with group by `sale_line_id`: ```text ValueError: Invalid field 'planned_hours' on model 'project.task' for 'planned_hours:sum' ``` ### Root cause The Gantt progress bar computation for the `sale_line_id` grouping performs a `_read_group()` aggregation on the `planned_hours` field of `project.task`. However, `planned_hours` was renamed to `allocated_hours` during the saas-16.5 migration, so the former field no longer exists on `project.task`. As a result, the aggregation raises a `ValueError`. Migration reference: https://github.com/odoo/upgrade/blob/e638c6ce00d9d8936d034ad7130fef51565b9195/migrations/project/saas~16.5.1.2/pre-migrate.py#L10 Issued PR: https://github.com/odoo/enterprise/pull/49685 ### Fix Use `allocated_hours`, the renamed equivalent of `planned_hours`, when computing the Gantt progress bar. This restores the Gantt view when grouping tasks by **Sale Order Item** and prevents the traceback. Forward-Port-Of: odoo/enterprise#122994 Forward-Port-Of: odoo/enterprise#122297
The timesheet assistant no longer shows an empty Unmatched section when all items in that group are filtered out as away-from-keyboard events. This avoids confusing users with a section header that has no visible content.
Original PR description
The Unmatched group's header renders even when its only entries are afk events, since those are filtered out at display time but still counted when checking if the group has content. With this PR, we first check if a group has visible content before displaying the header Task-6348666 Forward-Port-Of: odoo/enterprise#122900 Forward-Port-Of: odoo/enterprise#122858
The point-of-sale Urban Piper test data now includes the required product category so order preparation checks can run correctly. This prevents a known automated test failure and helps keep future releases stable without changing customer-facing behavior.
Original PR description
This commit fixes a failing `pos.prep.order` test assertion by assigns a PoS category to the products used in the test orders. The failure occurs because the products used in the order lines do not have a PoS category assigned. As a result, the preparation order generation process fails when creating the corresponding `pos.prep.order`. Runbot Error-[242023](https://runbot.odoo.com/odoo/runbot.build.error/242023)
Employees without a fixed or average working schedule will no longer see misleading expected hours in the Timesheet Assistant or systray. Total hours remain visible, reducing confusion for teams using variable or no scheduled working hours.
Original PR description
**Steps to reproduce:** 1. Create an employee without a fixed working schedule. 2. Configure the employee with variable hours per day, per week, or no working hours at all. 3. Open the Timesheet Assistant or the Timesheet systray. 4. Observe that expected hours are displayed (over 0h 00m or over 24h 00m). **Cause:** Expected working hours were always computed and displayed, even for resources without a fixed schedule. **Fix:** Only compute expected working hours when the employee has a fixed or average schedule, and rely on the computed working hours to control the display of expected hours while keeping total hours always visible. task-6321760 Forward-Port-Of: odoo/enterprise#122859 Forward-Port-Of: odoo/enterprise#122232
Pasting document links into an empty message no longer adds an unnecessary blank line at the start. Existing message text still stays separated from pasted links, keeping messages neat and readable.
Original PR description
Before this commit, adding document links always prepended a line break before the generated links. When the composer was empty, this resulted in messages starting with an unnecessary blank line. This commit only inserts a line break when the composer already contains text, avoiding the extra spacing while preserving the separation between existing content and pasted links. task-[5947683](https://www.odoo.com/odoo/project/1519/tasks/5947683) Forward-Port-Of: odoo/enterprise#120952
The Timesheet Assistant now checks whether timesheets are allowed on a matched project before offering to add time. This prevents users from starting timesheet entries for projects where timesheet tracking has been disabled, reducing confusion and invalid actions.
Original PR description
Before this commit, the Timesheet Assistant would display the "Add" button and attempt to prefill timesheet forms for activities matched to projects where the `allow_timesheets` setting was set to `False`. This commit updates the Timesheet Assistant logic to evaluate the project's configuration. When an activity is matched to a project that has `allow_timesheets=False`: - The "Add" button is hidden from the suggestion list. - The system prevents prefilling the timesheet creation form. Task: 6306203 Forward-Port-Of: odoo/enterprise#123071 Forward-Port-Of: odoo/enterprise#120890
New planning shifts now default to 8 AM to 4 PM in the user's own timezone instead of being shifted by UTC conversion. This prevents schedules from appearing at the wrong hours for employees in locations such as Belgium.
Original PR description
Before: When creating a new shift, we set 8 AM - 4 PM as the default hours in UTC. With the timezone in Belgium, this becomes 10 AM - 6 PM. After: Change the timezone of the new shift to match the user's timezone. This will make the hours always be from 8 to 4 (working hours) --- task-6285596 Forward-Port-Of: odoo/enterprise#120062
This fix prevents delivery tracking from failing when EasyPost sends an empty tracker value. Users can continue working without seeing an error when opening or processing shipments affected by this carrier response.
Original PR description
The PR https://github.com/odoo/enterprise/pull/111833 handled the specific case when the tracker data is missing from the EasyPost response, however in certain cases `tracker` key exists, but it has a `None` value, which leads to a traceback when trying to access the stock move:
```
File "/home/odoo/src/enterprise/18.0/delivery_easypost/models/easypost_request.py", line 392, in get_tracking_link
public_url = shipment.get('tracker', {}).get('public_url')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'get'
```
This commit provides a fallback to avoid getting the error from the side of the user.
opw-6270242
Forward-Port-Of: odoo/enterprise#119400Popovers in dark mode now display secondary buttons and embedded forms with clearer, consistent styling. This makes actions easier to recognize and keeps screens such as event slot creation visually aligned with the rest of the interface.
Original PR description
Before this commit, content like form & secondary button rendered inside popovers had inconsistent styling in dark mode: - secondary buttons did not stand out properly from the popover background, making them look like plain text blocks rather than actionable buttons; - forms rendered inside popovers (such as the multi-create popover) kept their default background, which visually clashed with the popover background. This commit fixes these issues by: - adding dedicated secondary button background colors for popovers, including hover state; - aligning form backgrounds inside popovers with the popover background. task-6249985 Forward-Port-Of: odoo/enterprise#121631
This fix prevents Hong Kong payroll payslips from crashing when a user clears the start or end date. The system now safely skips date-based wage and year-end pay calculations until the required dates are present, improving reliability during payroll editing.
Original PR description
Currently, an error occurs when a user removes the payslip date. **Steps to Reproduce:** - Install `l10n_hk_hr_payroll` with demo data. - Switch to the `Hong Kong` company. - Go to `Payroll` >…
Currently, an error occurs when a user removes the payslip date. **Steps to Reproduce:** - Install `l10n_hk_hr_payroll` with demo data. - Switch to the `Hong Kong` company. - Go to `Payroll` > `Payslips` > `Payslips`. - Create a `payslip` and remove the `start` or `end` period. **Error 1:** `TypeError: unsupported operand type(s) for +: 'bool' and 'relativedelta'` **Error2:** `AttributeError: 'bool' object has no attribute 'month'` When a user removes the start or end date of a payslip, the system computes the Average Daily Wage. Based on the payslip dates, it finds the previous year's payslips [1]. If the start or end date is not set, it raises an error [2]. For the second error, when computing whether to include EOY pay, it compares the company's EOY pay date with the end date's month. If the end date is not set, accessing its month raises an error [3]. This commit ensures that when retrieving previous-year payslips, if the start or end date is not set, it returns an empty payslip recordset. It also ensures that when computing whether to include EOY pay, if the end date is not set, `include_eoy_pay` is set to `False`. [1]: https://github.com/odoo/enterprise/blob/ec8a009794863090351d91650aff727e6fbeab7e/l10n_hk_hr_payroll/models/hr_payslip.py#L124 [2]- https://github.com/odoo/enterprise/blob/ec8a009794863090351d91650aff727e6fbeab7e/l10n_hk_hr_payroll/models/hr_payslip.py#L209-L215 [3]- https://github.com/odoo/enterprise/blob/ec8a009794863090351d91650aff727e6fbeab7e/l10n_hk_hr_payroll/models/hr_payslip.py#L141 Forward-Port-Of: odoo/enterprise#123135 Forward-Port-Of: odoo/enterprise#120586
Marketing Automation now shows the correct reason when a campaign participant is removed because they no longer match the campaign filter. This prevents users from seeing a misleading "Record deleted" message when the related record still exists, improving clarity during campaign follow-up.
Original PR description
`sync_participants` calls `action_set_unlink` on every participant whose record is no longer in the campaign domain, and `action_set_unlink` writes "Record deleted" on each scheduled trace. The…
`sync_participants` calls `action_set_unlink` on every participant whose record is no longer in the campaign domain, and `action_set_unlink` writes "Record deleted" on each scheduled trace. The removed bucket also contains records that still exist but no longer match the campaign filter, so the cancelled trace dialog shows "Record deleted" even when the record was only filtered out. In `sync_participants`, the to_remove participants are split between those whose record still exists in the database (filtered out by the campaign domain) and those whose record was actually deleted. `action_set_unlink` accepts an optional `trace_message` argument, defaulting to "Record deleted", and the filtered-out batch passes "Record no longer matches campaign filter" so the cancelled trace dialog reflects the real cause. Steps to reproduce: 1. Install Marketing Automation and CRM. 2. Open Marketing Automation, create a campaign on Lead with filter Stage = New. 3. Add a begin activity to the workflow. 4. Open CRM, create a Lead in the New stage. 5. Back in the campaign, click Generate Participants. 6. In the CRM pipeline, drag the Lead from New to Qualified. 7. Back in the campaign, click Generate Participants again. 8. Open the Participants smart button, click the participant for the moved Lead. 9. Click the cancelled activity in the workflow timeline. => The activity dialog shows "Error message: Record deleted" although the Lead still exists. Ticket [link](https://www.odoo.com/odoo/project/49/tasks/6251264) opw-6251264 Forward-Port-Of: odoo/enterprise#118692
Payroll processing now checks only the warnings that apply to the payslips being computed. This avoids unnecessary work during payroll runs and helps keep payslip calculations more efficient without changing the payroll results.
Original PR description
Ensure that we do not evaluate unnecessary warnings by only evaluating the warnings relevant to the payslips being computed; instead of evaluating all of them. task-6371828
This fix keeps Knowledge file navigation working consistently after a Chrome browser change. It preserves the previous behavior so users do not experience unexpected issues when scrolling to file content or related elements.
Original PR description
Since Chrome 150, scrolling methods like `scrollIntoView()` return a Promise instead of `undefined`. This commit adds block braces to ensure the action returns `undefined` and keeps the same behavior as before. Reference: - https://chromestatus.com/feature/5082138340491264 - https://chromium.googlesource.com/chromium/src/+/50f3e3d0a9bc02aad8b8161dbdd59046991dd2c7 runbot-941309 Forward-Port-Of: odoo/enterprise#123231 Forward-Port-Of: odoo/enterprise#123031
Grid view list titles now show the user-friendly label for grouped selection fields instead of internal technical values. This makes drill-down results easier to understand when users click the magnifier on grouped grid cells.
Original PR description
When grouping a grid view by a selection field and clicking on the cell magnifier, the list title showed the technical name (e.g. non_billable) instead of the display name (e.g. "Non Billable"). This commit adds a condition specifically for selection fields, ensuring that their display names are used. task-5980035 Forward-Port-Of: odoo/enterprise#122303 Forward-Port-Of: odoo/enterprise#120894
Fixed a problem that caused the appointment slot form to crash when users clicked the fields for limiting a slot to specific users or resources. This keeps appointment configuration usable and removes a broken filter that was not providing any benefit.
Original PR description
Clicking the "Restrict to User" or "Restrict to Resources" field on a slot crashed with:
invalid input syntax for type integer: "appointment_type_id.staff_user_ids"
The field domain was a quoted string instead of a list, so it was passed through as a literal value. Remove the domain: it never filtered anything and only broke the form.
opw-6349497
Forward-Port-Of: odoo/enterprise#122651The French Intrastat export wizard now opens only the journal entries that are actually missing required Intrastat information. This helps users resolve export warnings faster and avoids confusion from seeing unrelated entries.
Original PR description
Steps to reproduce: 1. Have a French company with intrastat report module installed 2. Create and validate a bill to another EU country, without filling out at least one of the required intrastat fields 3. Go to the intrastat report, and export it as XML DEBWEB2 4. In the export wizard, click on the internal links on the warning messages Issues: 1. In the Intrastat report in French localization, when there are missing values detected in the export, the Export Wizard shows internal links that lead to every journal entries - instead of showing only the relevant entries. The warning banner on the report uses the action action_invalid_code_moves which has a domain to limit what is shown on the view form. However in the method _fill_value_errors there was no domain. opw-6215339 Forward-Port-Of: odoo/enterprise#117997
This fix aligns the call debrief player tests with updated playback behavior, removing outdated timing workarounds. It helps ensure segment navigation in AI call debriefs remains reliable and reduces the chance of regressions in audio playback.
Original PR description
BACKPORT OF https://github.com/odoo/enterprise/pull/121951 The corresponding community commit has refactored the deferred seek synchronization in the CallDebrief component removing the reliance on the 'loadeddata' media event. Because of this, we don't need to manually trigger the event or wait for extra animation frames in this test anymore. This commit cleans them up to match the new behavior. task-6321435 Community counterpart https://github.com/odoo/odoo/pull/273733
Users can now close the installer and web watcher warning banners in the Timesheets Assistant without triggering an error. This keeps the interface responsive and prevents dismissed messages from staying visible unexpectedly.
Original PR description
Issue: - Closing the installer banner or the web watcher warning banner in the Timesheets Assistant raises an Owl error and leaves the banner visible. Cause: - Both buttons bind their handler with a bare method name, e.g. `t-on-click="onDismissConnectionWarning"`. Bare identifiers are resolved against the template rendering context, which no longer exposes component methods. Fix: - Reference the handlers through `this`. task-6373382
15 changes
Resolved issues and error corrections
Pasting document links into an empty message no longer adds an unnecessary blank line at the start. Messages look cleaner while still keeping links separated when text is already present.
Original PR description
Before this commit, adding document links always prepended a line break before the generated links. When the composer was empty, this resulted in messages starting with an unnecessary blank line. This commit only inserts a line break when the composer already contains text, avoiding the extra spacing while preserving the separation between existing content and pasted links. task-[5947683](https://www.odoo.com/odoo/project/1519/tasks/5947683) Forward-Port-Of: odoo/enterprise#120952
New planning shifts now use the employee or user's local timezone when setting default hours. This prevents shifts from appearing offset, such as 10 AM to 6 PM instead of the expected 8 AM to 4 PM, improving scheduling accuracy.
Original PR description
Before: When creating a new shift, we set 8 AM - 4 PM as the default hours in UTC. With the timezone in Belgium, this becomes 10 AM - 6 PM. After: Change the timezone of the new shift to match the user's timezone. This will make the hours always be from 8 to 4 (working hours) --- task-6285596 Forward-Port-Of: odoo/enterprise#120062
The live field service map no longer recalculates routes when the current user's position changes. This avoids unnecessary route processing and helps preserve routing service tokens without changing the displayed routes.
Original PR description
The routing fetching in `updateUserPosition` of the `MapModel` should not be triggered for the live map. Right now, when changing user position, the routes are fetched again. However, for the live map, this should have no effect on routes, as they start from the user pins instead of the current user's position. This will avoid computing all over routes and preserve tokens. task-6307279
This fix prevents delivery tracking from failing when EasyPost returns an empty tracker value. Users can continue viewing shipment information without encountering an error screen in affected delivery workflows.
Original PR description
The PR https://github.com/odoo/enterprise/pull/111833 handled the specific case when the tracker data is missing from the EasyPost response, however in certain cases `tracker` key exists, but it has a `None` value, which leads to a traceback when trying to access the stock move:
```
File "/home/odoo/src/enterprise/18.0/delivery_easypost/models/easypost_request.py", line 392, in get_tracking_link
public_url = shipment.get('tracker', {}).get('public_url')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'get'
```
This commit provides a fallback to avoid getting the error from the side of the user.
opw-6270242
Forward-Port-Of: odoo/enterprise#119400The Swiss payroll time off request form now consistently shows the start date field. This prevents confusion and ensures employees can always enter the required date regardless of the type of time off request.
Original PR description
The time off request view was showing the request_date_from field conditionally, which makes no sense as you would always need to pick a date for a time off no matter which unit the request uses. runbot-241099
The website now shows the exact discount percentage configured for subscription products when prices are displayed tax-included. This prevents customers from seeing an incorrect lower discount, such as 4% instead of 5%, due to rounding precision.
Original PR description
Steps to reproduce: 1. Install eCommerce and Subscriptions. 2. Create a 21% Excluded tax. 3. Create a subscription product with a price of 45 with 21% tax and enable "Accept One-Time" in the…
Steps to reproduce: 1. Install eCommerce and Subscriptions. 2. Create a 21% Excluded tax. 3. Create a subscription product with a price of 45 with 21% tax and enable "Accept One-Time" in the Recurring Prices tab. 4. Publish the product on the website under the Sales tab. 5. Create a pricelist for 6 months recurring with two lines: - If min quantity is 0, then 0% discount - If min quantity is 2, then 5% discount 6. Set "Display Product Prices" to "Tax Included" in the Settings. 7. Open the product on the website, select the 6-month plan, and increase quantity to 2. Issue: The discount percentage displayed on the website shows 4% instead of the configured 5%. Why this happens: In `_get_additionnal_combination_info`, the discount is reverse-calculated from the tax-included price vs the tax-included sales price. When the 21% tax is included to both prices, it introduces a floating-point precision loss (4.9954..%), which floor() then truncates to 4%. Fix: When the pricelist rule uses 'percentage' discount, read `percent_price` directly from the pricing rule instead of reverse-calculating from tax-adjusted prices, as it represents the exact discount percentage the merchant configured with no floating-point involvement. opw-6224735 Forward-Port-Of: odoo/enterprise#121654
Marketing Automation now shows the correct reason when a campaign participant is removed because they no longer match the campaign filter. This avoids misleading users with a "Record deleted" message when the underlying lead or record still exists.
Original PR description
`sync_participants` calls `action_set_unlink` on every participant whose record is no longer in the campaign domain, and `action_set_unlink` writes "Record deleted" on each scheduled trace. The…
`sync_participants` calls `action_set_unlink` on every participant whose record is no longer in the campaign domain, and `action_set_unlink` writes "Record deleted" on each scheduled trace. The removed bucket also contains records that still exist but no longer match the campaign filter, so the cancelled trace dialog shows "Record deleted" even when the record was only filtered out. In `sync_participants`, the to_remove participants are split between those whose record still exists in the database (filtered out by the campaign domain) and those whose record was actually deleted. `action_set_unlink` accepts an optional `trace_message` argument, defaulting to "Record deleted", and the filtered-out batch passes "Record no longer matches campaign filter" so the cancelled trace dialog reflects the real cause. Steps to reproduce: 1. Install Marketing Automation and CRM. 2. Open Marketing Automation, create a campaign on Lead with filter Stage = New. 3. Add a begin activity to the workflow. 4. Open CRM, create a Lead in the New stage. 5. Back in the campaign, click Generate Participants. 6. In the CRM pipeline, drag the Lead from New to Qualified. 7. Back in the campaign, click Generate Participants again. 8. Open the Participants smart button, click the participant for the moved Lead. 9. Click the cancelled activity in the workflow timeline. => The activity dialog shows "Error message: Record deleted" although the Lead still exists. Ticket [link](https://www.odoo.com/odoo/project/49/tasks/6251264) opw-6251264 Forward-Port-Of: odoo/enterprise#118692
Hong Kong payroll now handles payslips with missing start or end dates without crashing. This prevents interruptions when users edit payslip periods and ensures related wage and end-of-year pay calculations are safely skipped until valid dates are provided.
Original PR description
Currently, an error occurs when a user removes the payslip date. **Steps to Reproduce:** - Install `l10n_hk_hr_payroll` with demo data. - Switch to the `Hong Kong` company. - Go to `Payroll` >…
Currently, an error occurs when a user removes the payslip date. **Steps to Reproduce:** - Install `l10n_hk_hr_payroll` with demo data. - Switch to the `Hong Kong` company. - Go to `Payroll` > `Payslips` > `Payslips`. - Create a `payslip` and remove the `start` or `end` period. **Error 1:** `TypeError: unsupported operand type(s) for +: 'bool' and 'relativedelta'` **Error2:** `AttributeError: 'bool' object has no attribute 'month'` When a user removes the start or end date of a payslip, the system computes the Average Daily Wage. Based on the payslip dates, it finds the previous year's payslips [1]. If the start or end date is not set, it raises an error [2]. For the second error, when computing whether to include EOY pay, it compares the company's EOY pay date with the end date's month. If the end date is not set, accessing its month raises an error [3]. This commit ensures that when retrieving previous-year payslips, if the start or end date is not set, it returns an empty payslip recordset. It also ensures that when computing whether to include EOY pay, if the end date is not set, `include_eoy_pay` is set to `False`. [1]: https://github.com/odoo/enterprise/blob/ec8a009794863090351d91650aff727e6fbeab7e/l10n_hk_hr_payroll/models/hr_payslip.py#L124 [2]- https://github.com/odoo/enterprise/blob/ec8a009794863090351d91650aff727e6fbeab7e/l10n_hk_hr_payroll/models/hr_payslip.py#L209-L215 [3]- https://github.com/odoo/enterprise/blob/ec8a009794863090351d91650aff727e6fbeab7e/l10n_hk_hr_payroll/models/hr_payslip.py#L141 Forward-Port-Of: odoo/enterprise#123135 Forward-Port-Of: odoo/enterprise#120586
Popover content now looks more consistent and easier to use in dark mode. Secondary buttons stand out as clickable actions, and forms inside popovers better match the surrounding popover background.
Original PR description
Before this commit, content like form & secondary button rendered inside popovers had inconsistent styling in dark mode: - secondary buttons did not stand out properly from the popover background, making them look like plain text blocks rather than actionable buttons; - forms rendered inside popovers (such as the multi-create popover) kept their default background, which visually clashed with the popover background. This commit fixes these issues by: - adding dedicated secondary button background colors for popovers, including hover state; - aligning form backgrounds inside popovers with the popover background. task-6249985 Forward-Port-Of: odoo/enterprise#121631
This update makes the AI test suite skip markdown rendering checks when the optional markdown component is not installed. It helps avoid false failures in environments that do not include that optional dependency, improving reliability of validation without changing user-facing features.
Original PR description
markdown2 is an optional dependency, so `markdown_format` can fail to process markdown, in which case all the markdown tests fail. Skip the markdown rendering test if there's no markdown rendering to test. Forward-Port-Of: odoo/enterprise#123002
This fix keeps Knowledge file navigation working consistently after a Chrome browser change. It prevents an internal browser return-value change from altering how the app handles scroll actions, reducing the risk of small usability issues for users.
Original PR description
Since Chrome 150, scrolling methods like `scrollIntoView()` return a Promise instead of `undefined`. This commit adds block braces to ensure the action returns `undefined` and keeps the same behavior as before. Reference: - https://chromestatus.com/feature/5082138340491264 - https://chromium.googlesource.com/chromium/src/+/50f3e3d0a9bc02aad8b8161dbdd59046991dd2c7 runbot-941309 Forward-Port-Of: odoo/enterprise#123231 Forward-Port-Of: odoo/enterprise#123031
DHL deliveries could fail for customers or warehouses in regions whose province code was only one character, such as Barcelona. The DHL connector now sends the longer official province code where needed, helping shipments validate successfully.
Original PR description
Steps:
- Install delivery_dhl_rest
- Create a new customer with barcelona as address
- Create a new Delivery
- Set DHL
- Validate de delivery
- Validation error #/customerDetails/receiverDetails/postalAddress/provinceCode: expected minLength: 2, actual: 1
DHL requires `provinceCode` to be at least 2 characters. Several countries in `res.country.state` data use single-character codes (e.g. ES: B, M, A…; AR: C, B, S…; CN: 京, 沪…). This caused API validation errors when shipping from or to addresses in those regions.
Add `PROVINCE_CODE_MAP`, a dict keyed by `(country_ISO2, state_code)`, mapping each offending code to its ISO 3166-2 form (e.g. ('ES', 'B') -> 'ES-B'). Both `_get_consignee_vals` and `_get_shipper_vals` now look up the map before sending `provinceCode`, falling back to the raw code for countries not in the map.
links: https://developer.dhl.com/api-reference/mydhl-api-dhl-express#shipments
opw-6341745
Forward-Port-Of: odoo/enterprise#122138Grid views now display the user-friendly label for grouped selection values when opening details from the magnifier. This avoids confusing internal codes such as "non_billable" appearing in list titles, making navigation clearer for users.
Original PR description
When grouping a grid view by a selection field and clicking on the cell magnifier, the list title showed the technical name (e.g. non_billable) instead of the display name (e.g. "Non Billable"). This commit adds a condition specifically for selection fields, ensuring that their display names are used. task-5980035 Forward-Port-Of: odoo/enterprise#122303 Forward-Port-Of: odoo/enterprise#120894
The French Intrastat export wizard now opens only the journal entries related to missing required Intrastat values. This prevents users from being sent to a full list of entries, making it easier to find and correct the specific records blocking the export.
Original PR description
Steps to reproduce: 1. Have a French company with intrastat report module installed 2. Create and validate a bill to another EU country, without filling out at least one of the required intrastat fields 3. Go to the intrastat report, and export it as XML DEBWEB2 4. In the export wizard, click on the internal links on the warning messages Issues: 1. In the Intrastat report in French localization, when there are missing values detected in the export, the Export Wizard shows internal links that lead to every journal entries - instead of showing only the relevant entries. The warning banner on the report uses the action action_invalid_code_moves which has a domain to limit what is shown on the view form. However in the method _fill_value_errors there was no domain. opw-6215339 Forward-Port-Of: odoo/enterprise#117997
Fixes a crash when users click the restriction fields for users or resources on appointment slots. The broken filter was removed because it did not provide useful filtering and prevented the form from working correctly.
Original PR description
Clicking the "Restrict to User" or "Restrict to Resources" field on a slot crashed with:
invalid input syntax for type integer: "appointment_type_id.staff_user_ids"
The field domain was a quoted string instead of a list, so it was passed through as a literal value. Remove the domain: it never filtered anything and only broke the form.
opw-6349497
Forward-Port-Of: odoo/enterprise#1226518 changes
Resolved issues and error corrections
Pasting document links into an empty message no longer adds an unnecessary blank line at the start. This keeps shared document messages cleaner while still separating links from any existing text when needed.
Original PR description
Before this commit, adding document links always prepended a line break before the generated links. When the composer was empty, this resulted in messages starting with an unnecessary blank line. This commit only inserts a line break when the composer already contains text, avoiding the extra spacing while preserving the separation between existing content and pasted links. task-[5947683](https://www.odoo.com/odoo/project/1519/tasks/5947683) Forward-Port-Of: odoo/enterprise#120952
The AI module tests now skip markdown rendering checks when the optional markdown component is not installed. This prevents unnecessary test failures in environments that do not include that optional dependency, improving reliability for releases and maintenance.
Original PR description
markdown2 is an optional dependency, so `markdown_format` can fail to process markdown, in which case all the markdown tests fail. Skip the markdown rendering test if there's no markdown rendering to test.
This fix prevents delivery tracking from failing when EasyPost returns an empty tracker value. Users can continue processing shipments without encountering an unexpected error while viewing or generating tracking links.
Original PR description
The PR https://github.com/odoo/enterprise/pull/111833 handled the specific case when the tracker data is missing from the EasyPost response, however in certain cases `tracker` key exists, but it has a `None` value, which leads to a traceback when trying to access the stock move:
```
File "/home/odoo/src/enterprise/18.0/delivery_easypost/models/easypost_request.py", line 392, in get_tracking_link
public_url = shipment.get('tracker', {}).get('public_url')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'get'
```
This commit provides a fallback to avoid getting the error from the side of the user.
opw-6270242
Forward-Port-Of: odoo/enterprise#119400Restored and updated automated checks for rental and Kenyan stock valuation flows after earlier accounting valuation changes. This helps ensure stock receipts and vendor bill amounts stay aligned, reducing the risk of incorrect valuation-related behavior in future updates.
Original PR description
*: sale_stock_renting, l10n_ke_edi_oscu_stock Re-enable and adapt the tests skipped to fast merge the valuation refactoring made in 08b62a4bbcc6f9a391b2cc00a621ef4c76100229. The stock IO now values the receipt from the vendor bill, so the shared purchase fixtures `l10n_ke_edi_oscu` need to match the values provided in `l10n_ke_edi_oscu_stock` see for instance: https://github.com/odoo/enterprise/blob/ce68644f97ac28568b9497a18079a4ad5ce4a125/l10n_ke_edi_oscu/tests/expected_requests/save_purchase_2.json#L11-L13 Forward-Port-Of: odoo/enterprise#122857
The website now shows the exact discount percentage configured for subscription products when prices are displayed with tax included. This avoids confusing customers and merchants with rounded-down discounts, such as showing 4% instead of the intended 5%.
Original PR description
Steps to reproduce: 1. Install eCommerce and Subscriptions. 2. Create a 21% Excluded tax. 3. Create a subscription product with a price of 45 with 21% tax and enable "Accept One-Time" in the…
Steps to reproduce: 1. Install eCommerce and Subscriptions. 2. Create a 21% Excluded tax. 3. Create a subscription product with a price of 45 with 21% tax and enable "Accept One-Time" in the Recurring Prices tab. 4. Publish the product on the website under the Sales tab. 5. Create a pricelist for 6 months recurring with two lines: - If min quantity is 0, then 0% discount - If min quantity is 2, then 5% discount 6. Set "Display Product Prices" to "Tax Included" in the Settings. 7. Open the product on the website, select the 6-month plan, and increase quantity to 2. Issue: The discount percentage displayed on the website shows 4% instead of the configured 5%. Why this happens: In `_get_additionnal_combination_info`, the discount is reverse-calculated from the tax-included price vs the tax-included sales price. When the 21% tax is included to both prices, it introduces a floating-point precision loss (4.9954..%), which floor() then truncates to 4%. Fix: When the pricelist rule uses 'percentage' discount, read `percent_price` directly from the pricing rule instead of reverse-calculating from tax-adjusted prices, as it represents the exact discount percentage the merchant configured with no floating-point involvement. opw-6224735 Forward-Port-Of: odoo/enterprise#121654
Popovers in dark mode now display buttons and embedded forms with clearer, more consistent styling. This makes actions easier to identify and prevents form areas from visually clashing with the popover background.
Original PR description
Before this commit, content like form & secondary button rendered inside popovers had inconsistent styling in dark mode: - secondary buttons did not stand out properly from the popover background, making them look like plain text blocks rather than actionable buttons; - forms rendered inside popovers (such as the multi-create popover) kept their default background, which visually clashed with the popover background. This commit fixes these issues by: - adding dedicated secondary button background colors for popovers, including hover state; - aligning form backgrounds inside popovers with the popover background. task-6249985 Forward-Port-Of: odoo/enterprise#121631
Marketing Automation now shows the correct reason when a participant is removed from a campaign. If a record still exists but no longer matches the campaign filter, users will see that it was filtered out instead of incorrectly being told the record was deleted.
Original PR description
`sync_participants` calls `action_set_unlink` on every participant whose record is no longer in the campaign domain, and `action_set_unlink` writes "Record deleted" on each scheduled trace. The…
`sync_participants` calls `action_set_unlink` on every participant whose record is no longer in the campaign domain, and `action_set_unlink` writes "Record deleted" on each scheduled trace. The removed bucket also contains records that still exist but no longer match the campaign filter, so the cancelled trace dialog shows "Record deleted" even when the record was only filtered out. In `sync_participants`, the to_remove participants are split between those whose record still exists in the database (filtered out by the campaign domain) and those whose record was actually deleted. `action_set_unlink` accepts an optional `trace_message` argument, defaulting to "Record deleted", and the filtered-out batch passes "Record no longer matches campaign filter" so the cancelled trace dialog reflects the real cause. Steps to reproduce: 1. Install Marketing Automation and CRM. 2. Open Marketing Automation, create a campaign on Lead with filter Stage = New. 3. Add a begin activity to the workflow. 4. Open CRM, create a Lead in the New stage. 5. Back in the campaign, click Generate Participants. 6. In the CRM pipeline, drag the Lead from New to Qualified. 7. Back in the campaign, click Generate Participants again. 8. Open the Participants smart button, click the participant for the moved Lead. 9. Click the cancelled activity in the workflow timeline. => The activity dialog shows "Error message: Record deleted" although the Lead still exists. Ticket [link](https://www.odoo.com/odoo/project/49/tasks/6251264) opw-6251264 Forward-Port-Of: odoo/enterprise#118692
This fix preserves the expected behavior of Knowledge file navigation when using newer Chrome versions. It prevents an underlying browser change from altering how scroll actions complete, helping avoid small interaction glitches for users.
Original PR description
Since Chrome 150, scrolling methods like `scrollIntoView()` return a Promise instead of `undefined`. This commit adds block braces to ensure the action returns `undefined` and keeps the same behavior as before. Reference: - https://chromestatus.com/feature/5082138340491264 - https://chromium.googlesource.com/chromium/src/+/50f3e3d0a9bc02aad8b8161dbdd59046991dd2c7 runbot-941309 Forward-Port-Of: odoo/enterprise#123231 Forward-Port-Of: odoo/enterprise#123031
11 changes
Resolved issues and error corrections
Pasting document links into an empty message no longer adds an unnecessary blank line at the start. This keeps shared document messages cleaner while still separating links from any existing text.
Original PR description
Before this commit, adding document links always prepended a line break before the generated links. When the composer was empty, this resulted in messages starting with an unnecessary blank line. This commit only inserts a line break when the composer already contains text, avoiding the extra spacing while preserving the separation between existing content and pasted links. task-[5947683](https://www.odoo.com/odoo/project/1519/tasks/5947683) Forward-Port-Of: odoo/enterprise#120952
Previously paused checks for rental stock valuation and Kenyan electronic stock reporting have been restored and updated. This helps ensure stock values now align with vendor bill amounts, reducing the risk of incorrect reporting or inventory valuation going unnoticed.
Original PR description
*: sale_stock_renting, l10n_ke_edi_oscu_stock Re-enable and adapt the tests skipped to fast merge the valuation refactoring made in 08b62a4bbcc6f9a391b2cc00a621ef4c76100229. The stock IO now values the receipt from the vendor bill, so the shared purchase fixtures `l10n_ke_edi_oscu` need to match the values provided in `l10n_ke_edi_oscu_stock` see for instance: https://github.com/odoo/enterprise/blob/ce68644f97ac28568b9497a18079a4ad5ce4a125/l10n_ke_edi_oscu/tests/expected_requests/save_purchase_2.json#L11-L13 Forward-Port-Of: odoo/enterprise#122857
This fix prevents an error when EasyPost returns an empty tracking record while processing shipment tracking links. Users can continue working with deliveries without being interrupted by a system traceback in this edge case.
Original PR description
The PR https://github.com/odoo/enterprise/pull/111833 handled the specific case when the tracker data is missing from the EasyPost response, however in certain cases `tracker` key exists, but it has a `None` value, which leads to a traceback when trying to access the stock move:
```
File "/home/odoo/src/enterprise/18.0/delivery_easypost/models/easypost_request.py", line 392, in get_tracking_link
public_url = shipment.get('tracker', {}).get('public_url')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'get'
```
This commit provides a fallback to avoid getting the error from the side of the user.
opw-6270242
Forward-Port-Of: odoo/enterprise#119400Popover content now looks more consistent and easier to use in dark mode. Secondary buttons are more clearly visible as actions, and forms inside popovers better match the surrounding popover styling.
Original PR description
Before this commit, content like form & secondary button rendered inside popovers had inconsistent styling in dark mode: - secondary buttons did not stand out properly from the popover background, making them look like plain text blocks rather than actionable buttons; - forms rendered inside popovers (such as the multi-create popover) kept their default background, which visually clashed with the popover background. This commit fixes these issues by: - adding dedicated secondary button background colors for popovers, including hover state; - aligning form backgrounds inside popovers with the popover background. task-6249985 Forward-Port-Of: odoo/enterprise#121631
Marketing Automation now shows the correct reason when a campaign activity is cancelled because a record no longer matches the campaign filter. This prevents users from seeing a misleading “Record deleted” message when the underlying customer or lead record still exists.
Original PR description
`sync_participants` calls `action_set_unlink` on every participant whose record is no longer in the campaign domain, and `action_set_unlink` writes "Record deleted" on each scheduled trace. The…
`sync_participants` calls `action_set_unlink` on every participant whose record is no longer in the campaign domain, and `action_set_unlink` writes "Record deleted" on each scheduled trace. The removed bucket also contains records that still exist but no longer match the campaign filter, so the cancelled trace dialog shows "Record deleted" even when the record was only filtered out. In `sync_participants`, the to_remove participants are split between those whose record still exists in the database (filtered out by the campaign domain) and those whose record was actually deleted. `action_set_unlink` accepts an optional `trace_message` argument, defaulting to "Record deleted", and the filtered-out batch passes "Record no longer matches campaign filter" so the cancelled trace dialog reflects the real cause. Steps to reproduce: 1. Install Marketing Automation and CRM. 2. Open Marketing Automation, create a campaign on Lead with filter Stage = New. 3. Add a begin activity to the workflow. 4. Open CRM, create a Lead in the New stage. 5. Back in the campaign, click Generate Participants. 6. In the CRM pipeline, drag the Lead from New to Qualified. 7. Back in the campaign, click Generate Participants again. 8. Open the Participants smart button, click the participant for the moved Lead. 9. Click the cancelled activity in the workflow timeline. => The activity dialog shows "Error message: Record deleted" although the Lead still exists. Ticket [link](https://www.odoo.com/odoo/project/49/tasks/6251264) opw-6251264 Forward-Port-Of: odoo/enterprise#118692
This fix ensures the Frontdesk app includes the needed scheduling component for its timeline-style planning view. It prevents missing dependency issues so users can access the view without installation or loading errors.
Original PR description
runbot-237869
The POS now shows longpolling as the default IoT connection type instead of WebRTC. This avoids misleading users when their IoT setup does not support WebRTC, while still allowing WebRTC to appear once it is actually used.
Original PR description
Before this commit, the connection status for the IoT HTTP service was defaulting to "webrtc", at least until the first IoT call is made. This would lead to WebRTC being shown as the connection type in the POS even when using a new IoT image that doesn't support it. After this commit, we use "longpolling" as the default status, which is supported by all IoT images. If WebRTC is being used, that status will be set after the first action is performed. task-6366366 Forward-Port-Of: odoo/enterprise#123445
This update preserves the expected behavior of file navigation in Knowledge after a Chrome browser change. It prevents a minor compatibility issue where scrolling actions could return a different result than before, helping keep the user experience stable.
Original PR description
Since Chrome 150, scrolling methods like `scrollIntoView()` return a Promise instead of `undefined`. This commit adds block braces to ensure the action returns `undefined` and keeps the same behavior as before. Reference: - https://chromestatus.com/feature/5082138340491264 - https://chromium.googlesource.com/chromium/src/+/50f3e3d0a9bc02aad8b8161dbdd59046991dd2c7 runbot-941309 Forward-Port-Of: odoo/enterprise#123231 Forward-Port-Of: odoo/enterprise#123031
The French Intrastat export warning links now open only the journal entries related to missing required values. This helps users quickly find and correct the affected records instead of sorting through unrelated entries.
Original PR description
Steps to reproduce: 1. Have a French company with intrastat report module installed 2. Create and validate a bill to another EU country, without filling out at least one of the required intrastat fields 3. Go to the intrastat report, and export it as XML DEBWEB2 4. In the export wizard, click on the internal links on the warning messages Issues: 1. In the Intrastat report in French localization, when there are missing values detected in the export, the Export Wizard shows internal links that lead to every journal entries - instead of showing only the relevant entries. The warning banner on the report uses the action action_invalid_code_moves which has a domain to limit what is shown on the view form. However in the method _fill_value_errors there was no domain. opw-6215339 Forward-Port-Of: odoo/enterprise#117997
Grid views grouped by a selection field now show the readable label in the list title when users open a cell's details. This avoids exposing internal technical values and makes the screen clearer for end users.
Original PR description
When grouping a grid view by a selection field and clicking on the cell magnifier, the list title showed the technical name (e.g. non_billable) instead of the display name (e.g. "Non Billable"). This commit adds a condition specifically for selection fields, ensuring that their display names are used. task-5980035 Forward-Port-Of: odoo/enterprise#122303 Forward-Port-Of: odoo/enterprise#120894
Opening the restriction fields on appointment slots no longer causes an error. This fixes a broken form interaction so users can manage appointment slot restrictions without interruption.
Original PR description
Clicking the "Restrict to User" or "Restrict to Resources" field on a slot crashed with:
invalid input syntax for type integer: "appointment_type_id.staff_user_ids"
The field domain was a quoted string instead of a list, so it was passed through as a literal value. Remove the domain: it never filtered anything and only broke the form.
opw-6349497
Forward-Port-Of: odoo/enterprise#1226516 changes
Resolved issues and error corrections
This fix prevents delivery tracking from failing when EasyPost returns an empty tracking record. Users can continue processing shipments without seeing an unexpected error caused by missing carrier tracking details.
Original PR description
The PR https://github.com/odoo/enterprise/pull/111833 handled the specific case when the tracker data is missing from the EasyPost response, however in certain cases `tracker` key exists, but it has a `None` value, which leads to a traceback when trying to access the stock move:
```
File "/home/odoo/src/enterprise/18.0/delivery_easypost/models/easypost_request.py", line 392, in get_tracking_link
public_url = shipment.get('tracker', {}).get('public_url')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'get'
```
This commit provides a fallback to avoid getting the error from the side of the user.
opw-6270242
Forward-Port-Of: odoo/enterprise#119400This fix keeps Knowledge file actions working consistently after a Chrome browser change. It prevents a background browser behavior change from altering how the feature responds, preserving the previous user experience.
Original PR description
Since Chrome 150, scrolling methods like `scrollIntoView()` return a Promise instead of `undefined`. This commit adds block braces to ensure the action returns `undefined` and keeps the same behavior as before. Reference: - https://chromestatus.com/feature/5082138340491264 - https://chromium.googlesource.com/chromium/src/+/50f3e3d0a9bc02aad8b8161dbdd59046991dd2c7 runbot-941309 Forward-Port-Of: odoo/enterprise#123231 Forward-Port-Of: odoo/enterprise#123031
Grid view list titles now show the user-friendly label for grouped selection values, such as "Non Billable", instead of internal codes like "non_billable". This makes drill-down results easier to understand and reduces confusion for users reviewing grouped grid data.
Original PR description
When grouping a grid view by a selection field and clicking on the cell magnifier, the list title showed the technical name (e.g. non_billable) instead of the display name (e.g. "Non Billable"). This commit adds a condition specifically for selection fields, ensuring that their display names are used. task-5980035 Forward-Port-Of: odoo/enterprise#122303 Forward-Port-Of: odoo/enterprise#120894
The French Intrastat export wizard now opens only the journal entries related to missing required Intrastat information. This prevents users from being sent to unrelated accounting entries and makes it faster to identify and fix export issues.
Original PR description
Steps to reproduce: 1. Have a French company with intrastat report module installed 2. Create and validate a bill to another EU country, without filling out at least one of the required intrastat fields 3. Go to the intrastat report, and export it as XML DEBWEB2 4. In the export wizard, click on the internal links on the warning messages Issues: 1. In the Intrastat report in French localization, when there are missing values detected in the export, the Export Wizard shows internal links that lead to every journal entries - instead of showing only the relevant entries. The warning banner on the report uses the action action_invalid_code_moves which has a domain to limit what is shown on the view form. However in the method _fill_value_errors there was no domain. opw-6215339 Forward-Port-Of: odoo/enterprise#117997
Fixed an issue where selecting the "Restrict to User" or "Restrict to Resources" fields on appointment slots caused the form to crash. Removing the faulty filter keeps the slot form usable without changing how restrictions are applied.
Original PR description
Clicking the "Restrict to User" or "Restrict to Resources" field on a slot crashed with:
invalid input syntax for type integer: "appointment_type_id.staff_user_ids"
The field domain was a quoted string instead of a list, so it was passed through as a literal value. Remove the domain: it never filtered anything and only broke the form.
opw-6349497
Forward-Port-Of: odoo/enterprise#122651Users can now create an expense from a document even if their account is not linked to an employee record. They must still have permission to create expenses for another employee, so access controls remain in place while removing an unnecessary blocker.
Original PR description
Removes the constraint saying a user has to be linked to an employee to create an expense from a document. In this case, the user still needs the rights to create an expense for another employee. task-6237021 Forward-Port-Of: odoo/enterprise#123368 Forward-Port-Of: odoo/enterprise#118955
8 changes
Resolved issues and error corrections
This fix preserves the existing behavior of file-related navigation in Knowledge when users run newer Chrome versions. It prevents a browser change from unintentionally affecting how the Knowledge app handles scrolling actions.
Original PR description
Since Chrome 150, scrolling methods like `scrollIntoView()` return a Promise instead of `undefined`. This commit adds block braces to ensure the action returns `undefined` and keeps the same behavior as before. Reference: - https://chromestatus.com/feature/5082138340491264 - https://chromium.googlesource.com/chromium/src/+/50f3e3d0a9bc02aad8b8161dbdd59046991dd2c7 runbot-941309 Forward-Port-Of: odoo/enterprise#123231 Forward-Port-Of: odoo/enterprise#123031
Canceled appointment bookings no longer prevent businesses from lowering a resource's capacity. This avoids an error when updating resources after a booking has been canceled, keeping appointment management smoother and more accurate.
Original PR description
Steps to reproduce: 1. Install `appointment` 2. Create an appointment type using resources 3. Create a resource with capacity `4` 4. Book an appointment on that resource with reserved capacity `4` 5.…
Steps to reproduce: 1. Install `appointment` 2. Create an appointment type using resources 3. Create a resource with capacity `4` 4. Book an appointment on that resource with reserved capacity `4` 5. Try to reduce the resource capacity 6. Cancel the appointment 7. Try again to reduce the resource capacity Current behavior: - Reducing the resource capacity raises: `The capacity used can not be lesser than the capacity reserved` Issue: - Canceled appointments still prevent lowering the resource capacity, even though the booking is no longer active. Cause: - Canceling an appointment only archives the related `calendar.event`, it does not remove the corresponding `appointment.booking.line`. That booking line keeps its previous `capacity_reserved` value, while `capacity_used` is a stored computed field depending on the resource capacity. When the resource capacity is reduced after cancellation, the archived booking line is recomputed with the new lower resource capacity and this violates the SQL constraint Solution: - For inactive booking lines: Set `capacity_used = capacity_reserved` opw-6036053 Forward-Port-Of: odoo/enterprise#112485
This update prevents delivery tracking from failing when EasyPost returns an empty tracker value. Users can continue working without seeing an error while the system falls back safely when tracking link data is unavailable.
Original PR description
The PR https://github.com/odoo/enterprise/pull/111833 handled the specific case when the tracker data is missing from the EasyPost response, however in certain cases `tracker` key exists, but it has a `None` value, which leads to a traceback when trying to access the stock move:
```
File "/home/odoo/src/enterprise/18.0/delivery_easypost/models/easypost_request.py", line 392, in get_tracking_link
public_url = shipment.get('tracker', {}).get('public_url')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'get'
```
This commit provides a fallback to avoid getting the error from the side of the user.
opw-6270242
Forward-Port-Of: odoo/enterprise#119400Users can now create an expense from a document even if their account is not linked to an employee. They still need permission to create expenses for another employee, so the change removes an unnecessary blocker while keeping access controls in place.
Original PR description
Removes the constraint saying a user has to be linked to an employee to create an expense from a document. In this case, the user still needs the rights to create an expense for another employee. task-6237021 Forward-Port-Of: odoo/enterprise#118955
This fixes an issue in the Documents app where the selection bar could remain visible but stop working after moving between folders that contain the same file. Users can now continue selecting, clearing, or adding documents without switching views or clicking elsewhere to reset the page.
Original PR description
**Steps to reproduce:** - Install Documents app - Go to a folder and select a file - SelectionBox appears at the top - Click on another folder containing the same file (e.g. "All") - Box is still…
**Steps to reproduce:** - Install Documents app - Go to a folder and select a file - SelectionBox appears at the top - Click on another folder containing the same file (e.g. "All") - Box is still there, but interactions are broken (can't clear/add) - Going to another view type (kanban/list) or clicking elsewhere reset it **Issue:** `SelectionBox` doesn't update itself on folder changes, but `_reapplySelection` still tries to re-select the relevant records when switching folders (it was probably done to make it work when switching views, as it re-mount the component). **Fix:** Add current selected category to the `t-key` to trigger a re-rendering of the `SelectionBox` using a state with the current folder id. In 18.3 it was partially fixed in the same way by using the `targetRecords.length` in [1]. Feels like a hack (and we add a state just for this) but it ensures the component has the proper data for the current folder. We could also disable it on load for now, and we should make sure people don't accidentally use the state as the actual folder value... [1] https://github.com/odoo/enterprise/commit/8baaad621a1555680cd77ab514f626137b5b584d (Also a module update is needed to apply the fix due to the xml changes, so it might be better to apply it in master) opw-6348049
Opening the user or resource restriction fields on appointment slots no longer causes an error. The broken filter was removed because it did not limit choices and only prevented users from editing the form reliably.
Original PR description
Clicking the "Restrict to User" or "Restrict to Resources" field on a slot crashed with:
invalid input syntax for type integer: "appointment_type_id.staff_user_ids"
The field domain was a quoted string instead of a list, so it was passed through as a literal value. Remove the domain: it never filtered anything and only broke the form.
opw-6349497
Forward-Port-Of: odoo/enterprise#122651Grid view pop-up lists now display the user-friendly label for grouped selection fields instead of internal technical values. This makes drilled-down list titles clearer and easier for users to understand, especially for labels like "Non Billable".
Original PR description
When grouping a grid view by a selection field and clicking on the cell magnifier, the list title showed the technical name (e.g. non_billable) instead of the display name (e.g. "Non Billable"). This commit adds a condition specifically for selection fields, ensuring that their display names are used. task-5980035 Forward-Port-Of: odoo/enterprise#122303 Forward-Port-Of: odoo/enterprise#120894
Fixed the French Intrastat export warnings so their internal links open only the journal entries that actually have missing required information. This helps users correct export issues faster and avoids confusion from being sent to unrelated accounting entries.
Original PR description
Steps to reproduce: 1. Have a French company with intrastat report module installed 2. Create and validate a bill to another EU country, without filling out at least one of the required intrastat fields 3. Go to the intrastat report, and export it as XML DEBWEB2 4. In the export wizard, click on the internal links on the warning messages Issues: 1. In the Intrastat report in French localization, when there are missing values detected in the export, the Export Wizard shows internal links that lead to every journal entries - instead of showing only the relevant entries. The warning banner on the report uses the action action_invalid_code_moves which has a domain to limit what is shown on the view form. However in the method _fill_value_errors there was no domain. opw-6215339 Forward-Port-Of: odoo/enterprise#117997
2 changes
Resolved issues and error corrections
Canceled appointment bookings will no longer prevent staff from reducing a resource's capacity. This avoids an error after cancellations and keeps resource capacity management aligned with active bookings only.
Original PR description
Steps to reproduce: 1. Install `appointment` 2. Create an appointment type using resources 3. Create a resource with capacity `4` 4. Book an appointment on that resource with reserved capacity `4` 5.…
Steps to reproduce: 1. Install `appointment` 2. Create an appointment type using resources 3. Create a resource with capacity `4` 4. Book an appointment on that resource with reserved capacity `4` 5. Try to reduce the resource capacity 6. Cancel the appointment 7. Try again to reduce the resource capacity Current behavior: - Reducing the resource capacity raises: `The capacity used can not be lesser than the capacity reserved` Issue: - Canceled appointments still prevent lowering the resource capacity, even though the booking is no longer active. Cause: - Canceling an appointment only archives the related `calendar.event`, it does not remove the corresponding `appointment.booking.line`. That booking line keeps its previous `capacity_reserved` value, while `capacity_used` is a stored computed field depending on the resource capacity. When the resource capacity is reduced after cancellation, the archived booking line is recomputed with the new lower resource capacity and this violates the SQL constraint Solution: - For inactive booking lines: Set `capacity_used = capacity_reserved` opw-6036053 Forward-Port-Of: odoo/enterprise#112485
Twitter/X social stream posts now save the reply count provided by the platform's API. This ensures comments are shown alongside other engagement metrics, giving users a more complete view of tweet performance.
Original PR description
Twitter/X tweet metrics returned by the API include the number of replies in the `public_metrics.reply_count` field. This commit stores that value on social stream posts so the comments count can be displayed alongside other engagement metrics. API Documentation: https://docs.x.com/x-api/fundamentals/metrics#post-metrics Task-6251172 Forward-Port-Of: odoo/enterprise#120182
7 changes
Resolved issues and error corrections
The document selection window no longer shows document management actions that are not relevant when choosing files to attach or link. This reduces confusion and helps users focus on selecting the right documents.
Original PR description
When selecting documents for attachment/link, control panel actions were displayed upon selection. The document selection dialog uses the secondary documents view introduced in: https://github.com/odoo/enterprise/pull/89030/changes/f93c159c106d1dde70910ec590f8739e549b19cf Several document management actions were already hidden through the `documents_view_secondary` context, but `DocumentsAction` was still displayed upon selection. Hide `DocumentsAction` in the secondary view. Task-6236888 Forward-Port-Of: odoo/enterprise#122536 Forward-Port-Of: odoo/enterprise#119219
This fix ensures the recruitment reports feature includes the required component for cohort reporting. It prevents installation failures in specific setup scenarios, helping deployments complete smoothly.
Original PR description
installing hr_recruitment_reports with the --ski-auto-install flag causes an error. The error happens because it does not explicitly depend on web_cohort while displaying a cohort view. task-6352888 runbot_error-237854 Forward-Port-Of: odoo/enterprise#122432
The chatter now correctly shows the AI icon while an AI response is being prepared. This fixes a small visual issue so users can clearly recognize when the activity comes from the AI assistant.
Original PR description
This PR fixes an issue where the AI icon would not be shown on the thinking note of the chatter. The OWL3 migration added 'this.' prefixes to all template component references. This left 'isAiAgentChat' and 'props.channel' as bare context lookups (`ctx['isAiAgentChat']`, `ctx['props']`), both of which are undefined in the new rendering context. The fix adds 'this' in the xml to go through ctx['this'] to fetch each values correctly. task: 6346446 Forward-Port-Of: odoo/enterprise#122741
This update fixes an access problem affecting employee type handling in payroll tests. It helps keep payroll-related validation reliable and reduces the risk of incorrect test failures during development.
Original PR description
task-6348716 Forward-Port-Of: odoo/enterprise#122693 Forward-Port-Of: odoo/enterprise#122264
The invoice outstanding payments widget now displays payments in a consistent newest-first order using payment date and ID. This reduces confusion when users review available payments on invoices.
Original PR description
Before this commit: The invoice outstanding payments widget was not sorted by date globally, which could lead to confusion for users when viewing the widget. After this commit: This commit adds a sorting mechanism to ensure that the payments are displayed in descending order based on their date and ID. opw-6254080 Forward-Port-Of: odoo/enterprise#122964 Forward-Port-Of: odoo/enterprise#121642
The payroll payrun chatter panel and button will no longer appear in unrelated payroll views such as Time Offs. This prevents confusion by keeping payrun-specific discussion tools limited to the correct payrun screens.
Original PR description
The global `PayRunChatterService` was leaking state across shared views, causing the chatter panel and button to appear on views accessed outside the PayRun layout (e.g., via the main Payroll > Time Offs menu). Fix this by introducing a `useEffect` hook in `PayRunLayout` that checks for a valid `payrun_id` or `payRunReactive` state on view render. If absent, the chatter service state is explicitly reset and closed. The control panel button is also wrapped in a contextual `t-if` check, fully isolating the feature to its intended screens. Task : 6347871
Code cleanup and technical improvements
The Swedish SIE import tool was adjusted internally so related behavior can be extended more easily in the future. This does not introduce a user-facing change, but it improves maintainability for businesses that rely on custom accounting import flows.
Original PR description
We changed some tools to be regular model method to allow inheritance. task-none Forward-Port-Of: odoo/enterprise#121862
19 changes
Resolved issues and error corrections
Marketing Automation now shows the correct reason when a participant leaves a campaign because they no longer match the campaign filter. This avoids misleading users with a “Record deleted” message when the underlying CRM record still exists.
Original PR description
`sync_participants` calls `action_set_unlink` on every participant whose record is no longer in the campaign domain, and `action_set_unlink` writes "Record deleted" on each scheduled trace. The…
`sync_participants` calls `action_set_unlink` on every participant whose record is no longer in the campaign domain, and `action_set_unlink` writes "Record deleted" on each scheduled trace. The removed bucket also contains records that still exist but no longer match the campaign filter, so the cancelled trace dialog shows "Record deleted" even when the record was only filtered out. In `sync_participants`, the to_remove participants are split between those whose record still exists in the database (filtered out by the campaign domain) and those whose record was actually deleted. `action_set_unlink` accepts an optional `trace_message` argument, defaulting to "Record deleted", and the filtered-out batch passes "Record no longer matches campaign filter" so the cancelled trace dialog reflects the real cause. Steps to reproduce: 1. Install Marketing Automation and CRM. 2. Open Marketing Automation, create a campaign on Lead with filter Stage = New. 3. Add a begin activity to the workflow. 4. Open CRM, create a Lead in the New stage. 5. Back in the campaign, click Generate Participants. 6. In the CRM pipeline, drag the Lead from New to Qualified. 7. Back in the campaign, click Generate Participants again. 8. Open the Participants smart button, click the participant for the moved Lead. 9. Click the cancelled activity in the workflow timeline. => The activity dialog shows "Error message: Record deleted" although the Lead still exists. Ticket [link](https://www.odoo.com/odoo/project/49/tasks/6251264) opw-6251264
Popover content now looks more consistent and easier to use in dark mode. Secondary buttons stand out as clickable actions, and forms inside popovers better match the surrounding popover background.
Original PR description
Before this commit, content like form & secondary button rendered inside popovers had inconsistent styling in dark mode: - secondary buttons did not stand out properly from the popover background, making them look like plain text blocks rather than actionable buttons; - forms rendered inside popovers (such as the multi-create popover) kept their default background, which visually clashed with the popover background. This commit fixes these issues by: - adding dedicated secondary button background colors for popovers, including hover state; - aligning form backgrounds inside popovers with the popover background. task-6249985
Twitter/X posts now save the reply count provided by the platform API. This lets users see comment activity alongside other engagement metrics, giving a more complete view of post performance.
Original PR description
Twitter/X tweet metrics returned by the API include the number of replies in the `public_metrics.reply_count` field. This commit stores that value on social stream posts so the comments count can be displayed alongside other engagement metrics. API Documentation: https://docs.x.com/x-api/fundamentals/metrics#post-metrics Task-6251172 Forward-Port-Of: odoo/enterprise#120182
The Belgian POS blackbox daily report now targets the report period more reliably when applying its customization. This reduces the risk of report display issues if the underlying report layout changes.
Original PR description
In this commit: - Use the report period id in the inherited xpath instead of relying on the template structure. Community PR : https://github.com/odoo/odoo/pull/251425 Task [link](https://www.odoo.com/odoo/project.task/5980266) task-5980266
Facebook GIFs now appear in the comments modal of the social feed instead of showing as missing content. Since Facebook provides a still image and video link rather than the original GIF, users see the preview image and can click it to open the animation on Facebook.
Original PR description
Bug === When opening the comments modal of the feed view, the GIF images are not visible. Technical ========= The API does not return the GIF, it only returns the MP4 and the JPG. So we show the fixed image, and when clicking on it, it opens the video on Facebook. Task-6241607 Forward-Port-Of: odoo/enterprise#122871 Forward-Port-Of: odoo/enterprise#118619
This update fixes an automated test for field service reports that could fail because subtasks were checked in an unpredictable order. Sorting the tasks makes the test reliable again, helping maintain confidence in future updates without changing user-facing behavior.
Original PR description
Steps to Reproduce --- 1. Install industry_fsm_report. 2. Run the test test_subtasks_worksheet_template_id_duplicate Issue --- The test fails because it relies on positional index assertions (child_ids[0] and child_ids[1]). Since child_ids is now returned with the ordering (id desc), the subtasks are processed in a different order during copy, causing the assertions to no longer match the expected records. Fix --- Sort both the original and duplicated subtask recordsets by name. task-5966684 Forward-Port-Of: odoo/enterprise#123035
A small compatibility issue was fixed in the Expense Stripe integration so it works correctly with newer Python warning behavior. This helps prevent avoidable failures in environments using Python 3.13 or later, with no expected change to normal user workflows.
Original PR description
This commit fixes a missing message for a deprecated decorator introduced in commit odoo/enterprise@19693fd465ef8aff26896be1a2ab27486019e05e. This was failing only when the standard `warnings.deprecated` implementation was used (provided natively in Python 3.13+). runbot-941402
A small safeguard was restored in Knowledge to prevent a crash when a popover closes at the same time another action is running. This improves reliability for automated flows and users interacting with Knowledge dropdowns, without changing visible functionality.
Original PR description
This commit is a followup of [1] which made some tours fail ramdomly because of a crash. The crash occurred when `this.activeEl` was falsy, presumably because the popover was already closed. This commit only prevents the issue by adding a safe guard (which was there before [1] though). This commit is actually a backport of [2], which already fixed the issue as of saas-19.2 [1] https://github.com/odoo/enterprise/pull/114168 [2] https://github.com/odoo/enterprise/pull/115483 Runbot error~242907
The POS will now show the standard IoT connection method by default instead of incorrectly showing WebRTC before any IoT action has happened. This avoids confusing users when their IoT image does not support WebRTC, while still allowing WebRTC to appear once it is actually used.
Original PR description
Before this commit, the connection status for the IoT HTTP service was defaulting to "webrtc", at least until the first IoT call is made. This would lead to WebRTC being shown as the connection type in the POS even when using a new IoT image that doesn't support it. After this commit, we use "longpolling" as the default status, which is supported by all IoT images. If WebRTC is being used, that status will be set after the first action is performed. task-6366366
Knowledge article PDF downloads now exclude on-screen navigation menus and avoid showing scrollbars in the printed output. This makes exported articles look cleaner and more professional, especially for longer content or when the browser is zoomed in.
Original PR description
The Download PDF option of an article prints the page with the browser. On screen, the article body is inside .o_scroll_view_lg, which scrolls when the content is longer than the screen:…
The Download PDF option of an article prints the page with the browser. On screen, the article body is inside .o_scroll_view_lg, which scrolls when the content is longer than the screen: https://github.com/odoo/enterprise/blob/79f8defa04476e1b939dc8bb5449a775137aed62/knowledge/static/src/scss/knowledge_views.scss#L170-L177 The print stylesheet used to force overflow: visible on every div, so this container did not scroll when printing. It also hid every child of the body except the action manager, so the navbar and open dropdowns were left out of the print. Commit https://github.com/odoo/enterprise/commit/69612c80ea0aec5ccf2c2857449da03e61273457 rewrote knowledge_print.scss to scope its rules to the Knowledge view and removed both rules. The scroll container now keeps its fixed height and its scrollbar when printing, so the scrollbar is drawn in the print preview and on every page of the PDF. The dropdown opened to reach Download PDF is printed on top of the article when it overlaps the page area, which happens when the browser is zoomed in. Add overflow: visible to the print rule of knowledge_print.scss that already targets .o_scroll_view and .o_scroll_view_lg with position: static. That rule exists to undo the screen positioning of the scroll containers when printing, so the overflow reset belongs there. Its selector is also more specific than the screen one, so the value applies without !important, like position: static already does. Restore the rule that hides the body children other than the action manager, scoped to the Knowledge view like the rest of the file since the print stylesheet is now loaded on every page. Before: <img width="497" height="703" alt="image" src="https://github.com/user-attachments/assets/44aa3366-3fc8-4382-8aa2-84625fa4b6d8" /> After: <img width="497" height="703" alt="image" src="https://github.com/user-attachments/assets/8b6eb2bc-37a3-4666-b871-0e6149c41fea" /> Steps to reproduce: 1. Open the Knowledge app and create an article 2. Paste enough text in the article to fill more than one PDF page 3. Zoom the browser to 200% 4. Click the three dots in the top right corner, then Download PDF 5. Check the print preview or the saved PDF => A scrollbar is drawn on the right edge of every page and the dropdown menu is printed on top of the article Ticket [link](https://www.odoo.com/odoo/project.task/6279174) opw-6279174
This update prevents delivery tracking from failing when EasyPost returns an empty tracker value. Users can continue working without seeing an error caused by incomplete carrier tracking data.
Original PR description
The PR https://github.com/odoo/enterprise/pull/111833 handled the specific case when the tracker data is missing from the EasyPost response, however in certain cases `tracker` key exists, but it has a `None` value, which leads to a traceback when trying to access the stock move:
```
File "/home/odoo/src/enterprise/18.0/delivery_easypost/models/easypost_request.py", line 392, in get_tracking_link
public_url = shipment.get('tracker', {}).get('public_url')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'get'
```
This commit provides a fallback to avoid getting the error from the side of the user.
opw-6270242
Forward-Port-Of: odoo/enterprise#119400This fix keeps Knowledge page interactions working consistently after a browser behavior change in Chrome 150. It prevents internal scrolling actions from changing their expected result, reducing the risk of small interface issues for users on newer Chrome versions.
Original PR description
Since Chrome 150, scrolling methods like `scrollIntoView()` return a Promise instead of `undefined`. This commit adds block braces to ensure the action returns `undefined` and keeps the same behavior as before. Reference: - https://chromestatus.com/feature/5082138340491264 - https://chromium.googlesource.com/chromium/src/+/50f3e3d0a9bc02aad8b8161dbdd59046991dd2c7 runbot-941309 Forward-Port-Of: odoo/enterprise#123231 Forward-Port-Of: odoo/enterprise#123031
Grid views grouped by selection fields now show the user-friendly label in the list title when opening details from the cell magnifier. This prevents confusing technical values from appearing to users and makes grouped data easier to understand.
Original PR description
When grouping a grid view by a selection field and clicking on the cell magnifier, the list title showed the technical name (e.g. non_billable) instead of the display name (e.g. "Non Billable"). This commit adds a condition specifically for selection fields, ensuring that their display names are used. task-5980035 Forward-Port-Of: odoo/enterprise#122303 Forward-Port-Of: odoo/enterprise#120894
This update corrects a missing message text in the Stripe expense integration. It helps ensure users see the intended guidance or notification when working with Stripe-related expense categories.
Original PR description
Add missing string runbot-941402
The French Intrastat export wizard now opens only the journal entries related to missing required Intrastat values. This prevents users from being sent to all journal entries and makes it faster to correct export-blocking issues.
Original PR description
Steps to reproduce: 1. Have a French company with intrastat report module installed 2. Create and validate a bill to another EU country, without filling out at least one of the required intrastat fields 3. Go to the intrastat report, and export it as XML DEBWEB2 4. In the export wizard, click on the internal links on the warning messages Issues: 1. In the Intrastat report in French localization, when there are missing values detected in the export, the Export Wizard shows internal links that lead to every journal entries - instead of showing only the relevant entries. The warning banner on the report uses the action action_invalid_code_moves which has a domain to limit what is shown on the view form. However in the method _fill_value_errors there was no domain. opw-6215339 Forward-Port-Of: odoo/enterprise#117997
The point of sale payment screen now only runs India-specific invoice logic when the company is actually in India. This prevents avoidable errors in automated checks and keeps the invoice toggle working reliably for other countries.
Original PR description
Toggle invoice button was making a call in IN localization even when not in a IN country. This was causing an error in runbot 940146. This commit fixes the issue by checking if the country is IN before making the call. In `pos_settle_due` the method signature was not correct.
Fixes a crash that happened when users clicked the “Restrict to User” or “Restrict to Resources” fields on appointment slots. The broken filter was removed because it did not provide useful filtering and prevented the form from working correctly.
Original PR description
Clicking the "Restrict to User" or "Restrict to Resources" field on a slot crashed with:
invalid input syntax for type integer: "appointment_type_id.staff_user_ids"
The field domain was a quoted string instead of a list, so it was passed through as a literal value. Remove the domain: it never filtered anything and only broke the form.
opw-6349497
Forward-Port-Of: odoo/enterprise#122651Blank US checks now include the same stub lines as pre-printed checks, making printed checks easier to read and process. The check bottom layout was also adjusted so blank checks fit correctly on one page.
Original PR description
See individual commits. task-6359599 Forward-Port-Of: odoo/enterprise#123144
Fixed an issue where enabling FedEx return labels caused the original outgoing shipment to be treated like a return, leaving its reference field blank. Outbound FedEx labels now keep their reference information, making shipments easier to identify and track.
Original PR description
Issue ----- When setting the delivery method to create return labels aswell, the reference (`REF`) field is not present on the original outbound shipment. <img width="438" height="148" alt="image" src="https://github.com/user-attachments/assets/42acce7b-6177-4f8f-81d3-ad6dfd3e4bb2" /> Steps to reproduce ----- - Setup Fedex - Enable returns - Create a product (set weight) - Create a delivery for the product - Set carrier as Fedex - Validate delivery - Open the label > REF field is empty Cause ----- Fedex doesn't include references on the label of returns. When the option for returns is enabled, the outbound shipment is marked as a "Courtesy return". It doesn't make sense to specify a return reason on the original shipment. Expected outcome (after fix) ---- <img width="428" height="146" alt="image" src="https://github.com/user-attachments/assets/0d22e147-da90-4aa4-b3ca-2d996c7cc147" /> ----- Ticket: opw-6101620
2 changes
Resolved issues and error corrections
This fix prevents delivery tracking from failing when EasyPost returns an empty tracker value. Users can continue working without seeing an error when tracking information is incomplete or unavailable.
Original PR description
The PR https://github.com/odoo/enterprise/pull/111833 handled the specific case when the tracker data is missing from the EasyPost response, however in certain cases `tracker` key exists, but it has a `None` value, which leads to a traceback when trying to access the stock move:
```
File "/home/odoo/src/enterprise/18.0/delivery_easypost/models/easypost_request.py", line 392, in get_tracking_link
public_url = shipment.get('tracker', {}).get('public_url')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'get'
```
This commit provides a fallback to avoid getting the error from the side of the user.
opw-6270242
Forward-Port-Of: odoo/enterprise#119400This fix prevents an error when users propose adding a step from the Shop Floor for manufacturing orders whose bill of materials contains very similar operations. It helps production teams submit improvement suggestions reliably without being blocked by a system traceback.
Original PR description
[FIX] mrp_workorder_plm: avoid singleton traceback when matching BOM operations **Issue** Adding a step in a manufacturing order with two operations that are too similar could lead to a traceback…
[FIX] mrp_workorder_plm: avoid singleton traceback when matching BOM operations **Issue** Adding a step in a manufacturing order with two operations that are too similar could lead to a traceback when proposing an improvement from the Shop Floor. **Steps to reproduce** - Install the Product Lifecycle Management app. - Create a BOM for any product with two operations that: - Have the same name and work center - Have no variant - Create and confirm a Manufacturing Order for that product. - Open the Shop Floor view. - Click the gear icon -> Update Instructions -> Improvement Suggestion -> Add a Step -> Propose a Change. -> A traceback occurs **Cause** When adding a step: https://github.com/odoo/enterprise/blob/1c02615b73a2b4fb9f1ab91167a3c8d7c9ac824c/mrp_workorder_plm/models/mrp_workorder.py#L10 It tries to find the corresponding operation in the ECO's new BoM. This relies on `_get_sync_values()`: https://github.com/odoo/enterprise/blob/1c02615b73a2b4fb9f1ab91167a3c8d7c9ac824c/mrp_plm/models/mrp_routing.py#L9-L13 Because two operations share the same name, work center, and no variant, both match the filter: https://github.com/odoo/enterprise/blob/1c02615b73a2b4fb9f1ab91167a3c8d7c9ac824c/mrp_workorder_plm/models/mrp_workorder.py#L39 This results in a singleton error when accessing `operation.id`: https://github.com/odoo/enterprise/blob/1c02615b73a2b4fb9f1ab91167a3c8d7c9ac824c/mrp_workorder_plm/models/mrp_workorder.py#L42 opw-6241880
1 change
Resolved issues and error corrections
Canadian check printing now hides check numbers on payment stubs when pre-numbered checks are used. This keeps the printed stubs consistent with the checks themselves and avoids displaying duplicate or misleading numbers.
Original PR description
The check itself respected the check_manual_sequencing field, but the stubs did not. Hide the numbers on stubs as well, exactly like on US checks. task-6343701