Daily updates from Odoo
Tuesday, July 7, 2026
34 changes · saas-19.1
Enhancements to existing features
The VAT field now shows a cleaner placeholder and, when possible, the expected VAT format for the selected country. The help text was also simplified to make it easier for users to understand how to mark a customer without a Tax ID.
Original PR description
In this commit: - Remove 'or not applicable' and '/ if not applicable' from VAT placeholders. - Display the expected VAT format when available (e.g. BE0477472701). - Leave the placeholder empty when no format is known. - Simplify the tooltip to: 'You can use / to indicate that the customer has no Tax ID.' task-[5005896](https://www.odoo.com/odoo/project/967/tasks/5005896) Forward-Port-Of: odoo/odoo#273344
Resolved issues and error corrections
The Sales Commission Achievement report no longer crashes when users apply filters like Current Period that rely on relative dates such as today. This keeps commission reporting accessible and reliable without changing the intended reporting logic.
Original PR description
### Issue Applying a filter using relative date expressions (e.g. `today`) on the Sales Commission Achievement report raises a traceback. ### Steps to reproduce 1. Open **Sales > Commissions >…
### Issue Applying a filter using relative date expressions (e.g. `today`) on the Sales Commission Achievement report raises a traceback. ### Steps to reproduce 1. Open **Sales > Commissions > Achievements**. 2. Apply the **Current Period** filter. ### Current behavior The report crashes with: ```text ValueError: time data 'today' does not match format '%Y-%m-%d' ``` ### Cause The `_search` implementation extracts `date_to` values from the search domain and assumes they are literal `%Y-%m-%d` strings. However, search domains may contain relative date expressions such as `today`, `today +1d`, `today =1m`, etc., which cannot be parsed using `datetime.strptime()`. ### Fix Convert the incoming search domain to a `Domain` object and resolve it with `optimize_full()` before extracting the `date_to` values. This evaluates relative date expressions into actual `date` objects, preventing the traceback while preserving the existing currency conversion date logic. Forward-Port-Of: odoo/enterprise#122812
Hong Kong payroll now calculates payment in lieu of notice based on the employee's actual contract start date instead of assuming a full prior 12 months of work. This improves payroll accuracy for employees with shorter service periods and adds tests for related edge cases.
Original PR description
Currently, the calculation of the payment in lieu of notice is assuming the employee worked a whole 12 months prior to it being paid. This is of course not always going the be case, and when it happens our calculation is often incorrect. We update the salary rule to calculate a more accurate total days (which is no longer based on a fixed 12-month period but takes into account the contract's start date). We also now calculate the number of months more accurately by taking, once again, the contract's start date into account. Also adding a few test cases to test a bit more some special case we didn't yet test correctly. task-6348903 Forward-Port-Of: odoo/enterprise#122580
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 end-of-year pay calculations until valid dates are present, improving reliability during payslip 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#120586
This update fixes an error that could prevent Belgian CODA bank statement files from importing after a recent change added extra file information. Businesses using Belgian bank statement imports should see the process work reliably again without interruption.
Original PR description
in this commit: https://github.com/odoo/enterprise/commit/c66995fda83e19b28a38312af8efdc1601881cf0 we did a backport of the extension number. The backport adds the extension number to the return of the _parse_bank_statement_file. With that we have 4 args returned. Without the * we would have the "too many value to unpack" error opw-6362679 Forward-Port-Of: odoo/enterprise#123104
Adding recurring products through the product catalog now follows the same subscription plan validation as manually adding order lines. This prevents confirmed sales orders from accidentally including recurring products without a required subscription plan, reducing billing setup errors.
Original PR description
Steps to reproduce: --------------------------------------- 1. Install Subscription Module 2. Create and Confirm SO with no recurring plan and a non-recurring product 3. Add a recurring product >…
Steps to reproduce: --------------------------------------- 1. Install Subscription Module 2. Create and Confirm SO with no recurring plan and a non-recurring product 3. Add a recurring product > Save SO > Observe the User Error 4. Now add the same recurring product through Catalog View Observation: --------------------------------------- No User Error raised stating 'You cannot save a sale order with recurring product and no subscription plan.' Issue: --------------------------------------- When you manually add a line and click 'Save', the constraint (`_constraint_subscription_plan`) is triggered and raised `UserError` https://github.com/odoo/enterprise/blob/434d88960abb5e424fdc1106fc93935d328bff78/sale_subscription/models/sale_order.py#L176-L177 When you add a product via the catalog view, it calls `_update_order_line_info` which directly creates/updates order lines, Which do not trigger the python constraint. https://github.com/odoo/odoo/blob/ef9772bba1515bdaf5410c3af5a3e395f562d513/addons/sale/models/sale_order.py#L1926-L1933 Solution: --------------------------------------- Two private helpers are introduced: * `_is_exempt_from_subscription_plan_check`: single source of truth for all exempt states (draft, cancelled, upsell, and legacy upgrade orders). * `_check_recurring_plan_mismatch`: raises a `UserError` when the order has or will have a recurring product but no subscription plan, reusing the exemption helper so both call sites stay in sync. `_constraint_subscription_plan` is refactored to delegate to these helpers, and `_update_order_line_info` is overridden to call `_check_recurring_plan_mismatch` before the catalog update is applied, ensuring consistent validation across both entry points. opw-6194865 Forward-Port-Of: odoo/enterprise#122799 Forward-Port-Of: odoo/enterprise#117879
Task progress in the Gantt view now displays at the correct scale. This makes planned versus completed work visually accurate, so users can quickly understand task progress from the chart.
Original PR description
Steps to reproduce: ------------------------------------------- 1. Install the Timesheet module with demo data 2. Go to any FSM task > set allocated hours to 20h 3. Fill the timesheet for the same…
Steps to reproduce: ------------------------------------------- 1. Install the Timesheet module with demo data 2. Go to any FSM task > set allocated hours to 20h 3. Fill the timesheet for the same task for 10h 4. Navigate to FSM > My Tasks > Gantt view Observation: ------------------------------------------- Look at the task on the Gantt chart. The shading is barely visible because it covers only 0.5% of the bar, not 50% Issue: ------------------------------------------- In the commit https://github.com/odoo/odoo/pull/137570/changes/4a93d9aee957dd3feb3db0cb69eb3b8f0f4a4683 The progress field computation was changed from storing percentage values (0-100) to storing decimal values (0-1). Specifically, the `_compute_progress_hours` method was modified. This change was made to standardize the progress field storage format, with the understanding that the UI layer would multiply by 100 when displaying the value. While most views (form, list, kanban, etc.) were updated to multiply the progress by 100 for display purposes, the Gantt view's pill progress bar was missed. Solution: ------------------------------------------- Overrides the `enrichPill` method to multiply the `_progress` value by 100 before it's passed to the template. This ensures the Gantt pill progress bars display correctly without modifying the core web_gantt module. Before --------------------------- <img width="268" height="368" alt="image" src="https://github.com/user-attachments/assets/6d35927f-bd3f-47fc-9101-e2e188d419b8" /> After: -------------------------- <img width="250" height="371" alt="image" src="https://github.com/user-attachments/assets/fe7133e0-26d1-4c5f-b903-48826fda9488" /> opw-6038983 Forward-Port-Of: odoo/enterprise#122899 Forward-Port-Of: odoo/enterprise#111270
Unmatched Activity Watch events are now grouped consistently in Timesheets, even when project or task details are missing. This prevents duplicate unmatched groups and gives users a cleaner, more accurate timesheet review experience.
Original PR description
Before this commit, we could have 2 unmatched groups, one with `{project_id: false, task_id: false}` as key and another one with `{}` as key because the key events from AW do not always have `project_id` and `task_id` in their data.
This commit manages the case where `project_id` and `task_id` are not attributes of the activity watch event object to correctly set `{project_id: false, task_id: false}`.
task-6306218EC Sales List returns are now created separately for each company in a tax unit using that company's own VAT number. This prevents multiple entities from being incorrectly combined into one declaration, improving compliance and reporting accuracy.
Original PR description
Issue: The EC Sales List return is currently generated under the tax unit VAT number, consolidating all member entities into a single declaration. Expected: The EC Sales List return must be generated individually per member entity, each under their own VAT number, even when those entities belong to a tax Unit. Fix: Apply tax unit only if report's multi company filter is `tax_units`. Ref: https://github.com/odoo/enterprise/blob/07e8aba8604319747a5925c83576095ce9a63f9e/account_reports/models/account_return.py#L316-L317 task-6069402 Forward-Port-Of: odoo/enterprise#115974
Fixed invoice status handling for Field Service sales orders that include zero-price items. Free items added during a field service task are now treated as included, while free items already on the original quote still follow the normal invoicing process, preventing orders from staying incorrectly open or being skipped incorrectly.
Original PR description
## [FIX] industry_fsm_sale: fix invoice status for zero price lines ### Issue: Without Anglo-Saxon accounting, the system incorrectly sets the invoice status of all zero price sales order lines…
## [FIX] industry_fsm_sale: fix invoice status for zero price lines
### Issue:
Without Anglo-Saxon accounting, the system incorrectly sets the invoice status of all zero price sales order lines linked to an FSM task to 'no'
This includes pre-existing lines that were already present on the quotation before confirmation. If a zero price line is pre-existing, it should follow the standard flow and be marked as 'to invoice'
Only lines added as materials from the field service task at a zero price should be considered included in the price and marked as 'no'
### Cause:
In `SaleOrderLine._compute_invoice_status`, the system forced `invoice_status = 'no'` for all zero price lines when Anglo-Saxon accounting was disabled
It failed to check if the lines were actually materials added via the FSM task or original quotation lines
### Fix:
A new `material_sale_lines` compute field is added to `project.task` to distinctly isolate and track lines added specifically as materials during the task execution
In `SaleOrderLine._compute_invoice_status`, the logic is updated to ensure that only zero price lines identified as FSM materials are set to 'no' when Anglo-Saxon accounting is disabled
Other pre-existing zero price lines properly remain as 'to invoice'
### Steps to reproduce:
- Install `industry_fsm_sale`
- In Settings > Users & Companies > Companies > Any company, add the field Anglo-Saxon using Studio (In 19.0+)
- Disable Anglo-Saxon on the current company
- Create a product Service (Fixed Price, that create a task in a Field Service Project)
- Create and confirm a Sale Order with the Service and one product with unit price 0
Before the fix, the pre-existing SO line with price 0 is
incorrectly considered as not to invoice ('no')
opw-6169802
------------------------------
## [FIX] industry_fsm_sale: sync sale order invoice status
### Issue:
When a sale order contains FSM material lines with a price of zero and Anglo-Saxon accounting is disabled, the overall sale order invoice status remains stuck on 'to invoice' even after all other invoiceable lines are fully invoiced
### Cause:
The standard `SaleOrder._compute_invoice_status` does not handle FSM business rules regarding zero price material lines that are marked as `invoice_status = 'no'`
Because these lines are never technically invoiced, the global order status fails to transition to 'invoiced'
### Fix:
Override `SaleOrder._compute_invoice_status` to recompute the status of confirmed orders linked to FSM tasks
We use the task's `material_sale_lines` to filter out material components
If all lines on the order are either 'invoiced' or are zero price FSM material lines with Anglo-Saxon disabled, the global sale order status is forced to 'invoiced'
### Steps to reproduce:
- Install `industry_fsm_sale`
- In Settings > Users & Companies > Companies > Any company, add the field Anglo-Saxon using Studio (In 19.0+)
- Disable Anglo-Saxon on the current company
- Create a product Service (Fixed Price, that create a task in a Field Service Project)
- Create and confirm a Sale Order with the Service and one product with unit price 0
- Add a Product from the Task (Use a price 0 product, or set the unit price to 0 on the SO)
- Create the invoice for the Sale Order
Before the fix, the Service and Pre-existing product are invoiced, but in the Other Info Tab of the SO, the status stays on 'To Invoice' instead of 'Fully Invoiced'
opw-6169802
Forward-Port-Of: odoo/enterprise#119238Helpdesk teams that limit automatic ticket closure to certain stages will now only send closure reminder emails for tickets in those stages. This prevents customers from receiving misleading warnings for tickets that are not scheduled to be closed.
Original PR description
**Problem:** When a team restricts automatic closing to specific stages (from_stage_ids), the closing-reminder email is still sent to every inactive ticket in the team, including tickets in stages…
**Problem:** When a team restricts automatic closing to specific stages (from_stage_ids), the closing-reminder email is still sent to every inactive ticket in the team, including tickets in stages that are never auto-closed. **Steps to reproduce:** 1. On a helpdesk team, enable Automatic Closing with a reminder and set "In Stages" (from_stage_ids) to one specific stage 2. Leave a ticket inactive in a different, non-folded stage until it reaches the reminder threshold (auto_close_day - reminder_delay) **Current behavior:** The ticket gets a "your ticket will be closed soon" reminder even though it is not in an auto-close stage and will never be closed. **Expected behavior:** Only tickets that would actually be auto-closed (those in from_stage_ids) should receive the reminder. **Cause of the issue:** The reminder selection filters on auto_close_ticket_reminder and the reminder date only; unlike the auto-close selection, it does not apply the team's from_stage_ids condition. **Fix:** Reuse the same stage condition used to select tickets for closing when selecting tickets for the reminder, so the reminded set stays consistent with the set that will be auto-closed. opw-6291237
This fix restores support for portal users to archive or unarchive documents when the action is performed through trusted system flows. It prevents legitimate document workflows from being blocked while keeping normal access restrictions in place.
Original PR description
In #116886, we fixed the blocking of portal users to (un)archive documents, but it appears that some flows relied on it and we were lacking a way of supporting it. Backport of #123015 Task-6205627 Forward-Port-Of: odoo/enterprise#123164 Forward-Port-Of: odoo/enterprise#123030
The Mexican electronic invoicing process now correctly schedules another status update when more documents remain to be checked. This helps ensure all CFDI invoices are processed instead of leaving some waiting after a batch run.
Original PR description
Steps to reproduce ----------------- - Install l10n_mx_edi; - Switch to the mexican company; - Create 3 invoices for the mexican company (you will need to set an UNSPSC code on the products); - Send them to CFDI; - Go to the scheduled action "Automatic update of state on the SAT" and add "batch_size=2" to the method's parameters; - Manually run the cron; - Only two invoices will be updated, the cron is not retriggered to process the remianing one. Why is it hapening ------------------ We set a limit of batch_size + 1 in the search method, and the cron is retriggered if and only if the number of documents fetched is equal to the batch size, meaning there is no more documents to fetch. This should be triggered if we fetched more documents than the batch size. opw-6328118 Forward-Port-Of: odoo/enterprise#122659
Twitter/X reply counts are now saved for social stream posts when metrics are fetched from the API. This ensures comment counts appear 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
This fix ensures generated website pages use the correct dynamic snippet filters regardless of the order in which modules were installed. It prevents snippets from showing the wrong content and makes website generation more reliable for customers.
Original PR description
Our default dynamic snippets filter ids are set based on the order that we install our modules. This can cause issues if the user installs their modules in a different order. To fix this, we need to update the data-filter-id value to the correct value of the DB. To be able to do this, we also change the regex replacement to use lxml instead since it's much simpler. Lxml part from 799f83575e162eb683cfaebb4eb602ccc1fbe466. Forward-Port-Of: odoo/enterprise#122671
The task Gantt view now loads correctly when users group tasks by sales order item. This prevents an error caused by an outdated hours field and restores progress information in that view.
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#122712 Forward-Port-Of: odoo/enterprise#122297
Uploaded WebP images are now checked against the same maximum resolution limit as other image formats. This prevents very large images from being accepted by mistake, helping keep uploads consistent and avoiding oversized files on the platform.
Original PR description
Since 17.0, `webp` images can be uploaded at any resolution, whereas every other format is refused above IMAGE_MAX_RESOLUTION (50 Mpx) when the attachment is created on the server. Root cause…
Since 17.0, `webp` images can be uploaded at any resolution, whereas every other format is refused above IMAGE_MAX_RESOLUTION (50 Mpx) when the attachment is created on the server. Root cause =========== `ImageProcess` grouped webp together with empty sources and SVG and set `self.image = False`, returning before the `verify_resolution` check. As a result the resolution limit enforced for `png/jpeg/...` was never applied to `webp`. Fix === Split `webp` out of the skip branch: it is still not processed as before, but its resolution is now read from the RIFF header with `get_webp_size()` and checked against `IMAGE_MAX_RESOLUTION`, so oversized webp images are refused on upload like any other format. Steps to reproduce =================== 1. Edit any page with the website editor 2. Upload a `webp` image larger than 50 Mpx (e.g. 8000x8000) => The image is accepted, while a `png/jpeg` of the same size is refused task-4134430 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273570 Forward-Port-Of: odoo/odoo#273010
Previewing the “2Fa New Login” email template now works without triggering an error. This prevents interruptions for administrators who want to review or reset the template, while keeping the 2-factor login flow unchanged.
Original PR description
Issue: ---------------------------------------- Clicking "Preview" on the template "2Fa New Login" causes an error. Steps to reproduce: ---------------------------------------- - Search for the mail template "Settings: 2Fa New Login" - Click "Preview" - Error in terminal - From 17.0+ the error shows in UI - From saas-18.3+, a traceback occurs whe resetting the template Cause: ---------------------------------------- There is an assert the method `_get_totp_mail_code()` to ensure it's used during 2FA. But when passing by rendering this template in preview we aren't in sudo and the assert in `_get_totp_mail_code()` raises. Solution: ---------------------------------------- We replace the `assert` by a `if` which will return fake results. opw-6333887 Forward-Port-Of: odoo/odoo#273914 Forward-Port-Of: odoo/odoo#273125
This fixes an issue where selling and dropshipping a kit could leave a component’s cost incorrectly set to zero after delivery. The correction ensures the supplier cost is properly carried through so inventory valuation stays accurate for AVCO/FIFO products.
Original PR description
**Issue** Selling a kit with dropshipping in AVCO/FIFO could wrongly set the standard_price of the component product to 0 after validating the dropship transfer. **Steps to reproduce** - Create a kit…
**Issue** Selling a kit with dropshipping in AVCO/FIFO could wrongly set the standard_price of the component product to 0 after validating the dropship transfer. **Steps to reproduce** - Create a kit and component product - Activate MTO and dropship route for the kit - Activate dropship route for the component - Add a vendor for the component (ex: 100 dollars) - Set component to AVCO valuation - Create and confirm a sale order - Confirm the associate purchase order and the dropship transfer - Go to the product -> The standard price is still 0 instead of being updated from the supplier price. **Cause** While confirming the PO, a picking is created: https://github.com/odoo/odoo/blob/43f5ceadbc1f7df9898c327bf65bffdbe9860c1c/addons/purchase_stock/models/purchase_order.py#L371 With its associated moves: https://github.com/odoo/odoo/blob/43f5ceadbc1f7df9898c327bf65bffdbe9860c1c/addons/purchase_stock/models/purchase_order.py#L383 During the move preparation, the `cost_share` is not propagated on the generated move values, so it remains equal to 0. The `cost_share` is computed while exploding the kit BOM: https://github.com/odoo/odoo/blob/43f5ceadbc1f7df9898c327bf65bffdbe9860c1c/addons/purchase_mrp/models/purchase.py#L94 https://github.com/odoo/odoo/blob/43f5ceadbc1f7df9898c327bf65bffdbe9860c1c/addons/mrp/models/mrp_bom.py#L463 https://github.com/odoo/odoo/blob/43f5ceadbc1f7df9898c327bf65bffdbe9860c1c/addons/purchase_mrp/models/mrp_bom.py#L62 https://github.com/odoo/odoo/blob/43f5ceadbc1f7df9898c327bf65bffdbe9860c1c/addons/purchase_mrp/models/mrp_bom.py#L70 However, only the `bom_line_id` is propagated on the move values: https://github.com/odoo/odoo/blob/43f5ceadbc1f7df9898c327bf65bffdbe9860c1c/addons/purchase_mrp/models/purchase.py#L94-L99 Later, while validating the dropship transfer: https://github.com/odoo/odoo/blob/43f5ceadbc1f7df9898c327bf65bffdbe9860c1c/addons/stock_account/models/stock_move.py#L177 the move value is used to recompute the standard price: https://github.com/odoo/odoo/blob/43f5ceadbc1f7df9898c327bf65bffdbe9860c1c/addons/stock_account/models/product.py#L651 While `move.value` is not zero, `move._get_value` is: https://github.com/odoo/odoo/blob/cac987867b083355d3366228d0c551b34f366d92/addons/stock_account/models/product.py#L485-L487 since it depends on the move `cost_share`: https://github.com/odoo/odoo/blob/43f5ceadbc1f7df9898c327bf65bffdbe9860c1c/addons/purchase_mrp/models/stock_move.py#L25 Since the move `cost_share` is 0, the AVCO/FIFO recomputation uses an incorrect value and the component standard price is not updated. **Solution** No need to use `cost_share` to compute the value if the price_unit is already given for the component opw-6176571 Forward-Port-Of: odoo/odoo#264341
When the app loses connection, users can now keep navigating Discuss channels and access some channel details instead of having all actions blocked. This makes it easier to review locally available messages, members, pinned posts, attachments, and threads while temporarily offline.
Original PR description
Before this commit, when losing connection to the server, the "Offline UI" introduced in [1] would disable all buttons in Discuss. This prevents navigating the Discuss channels, even if we potentially have local knowledge of the messages in those channels. It also prevents using Thread actions like: - Channel Members - Pinned Messages - Attachments - Threads Which may also only need data that is available locally. This commit fixes the issue by marking the appropriate buttons as available offline (`data-available-offline`), which prevents the Offline UI service from disabling them. [1] https://github.com/odoo/odoo/pull/229492 task-6185454
The parallax-to-bottom intensity slider now accepts custom values correctly instead of snapping back to the default minimum. This fixes a usability issue that prevented users from fine-tuning the effect as intended.
Original PR description
`BuilderRange` supported inverted ranges (`props.min > props.max`) to keep the slider direction consistent across options, which was the case for the `Parallax to Bottom` (`min="-0.15" / max="-3"`) with `get min()`/`get max()` normalizing the bounds and `o_we_inverted_range` flipping the direction whenever `props.min > props.max` was detected. For the Bottom case, any value smaller than `-0.15` (e.g. `-1.5`) satisfied `value < props.min` and was clamped back to `-0.15`, making custom intensities impossible. Since this is the only inverted `BuilderRange` in the codebase, we restored the right order for the min/max, dropped the getters and replaced them with a prop to apply the `o_we_inverted_range` class in this scenario only. task-6058500 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Paymob has unexpectedly stopped operating in Pakistan, and its payment APIs no longer work there. This update removes Pakistan as a supported country for the Paymob payment provider so customers are not offered a broken payment option.
Original PR description
Paymob stopped their operations in Pakistan unexpectedly. Domain was dropped so none of the APIs work for Pakistan. Therefore we are removing the support of Pakistan in the Paymob provider. See Also: https://github.com/odoo/documentation/pull/18768 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273935
This change corrects an automated test related to Italian e-invoicing withholding. It does not introduce new business behavior, but helps ensure the existing feature is verified correctly and stays reliable after related updates.
Original PR description
This commit just want to correct a test of a PR already merged. Original commit: 78ffb5a2e63401123e4506056493e52cf3e69953 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274062
This fix makes the system correctly detect links that point to local addresses such as localhost. As a result, these links will be handled like other web links instead of being ignored, which improves testing and local development workflows.
Original PR description
Before this commit, url like `http://localhost:8069` were ignored by the `urlRegexp` because it requires a Top-Level Domain. This commit makes the Top-Level Domain optional. Forward-Port-Of: odoo/odoo#274379
Fixed an issue where recurring calendar events synced from Google could create one extra event on the final allowed day for users in timezones behind UTC. This keeps Odoo aligned with Google Calendar and avoids duplicate meetings appearing after a series is shortened.
Original PR description
When Google sends a recurrence with UNTIL in UTC (UNTIL=...Z), users in timezones behind UTC can get one extra occurrence on the boundary day. Google's UNTIL represents the last allowed start in UTC,…
When Google sends a recurrence with UNTIL in UTC (UNTIL=...Z), users in timezones behind UTC can get one extra occurrence on the boundary day. Google's UNTIL represents the last allowed start in UTC, but that UTC date fell into the previous local day. Because Odoo was comparing event start times as naive local datetimes against a cutoff derived from the wrong date, the boundary occurrence passed the check and was created. Steps to reproduce: 1. Set the user's timezone to a UTC-negative offset (e.g. America/Argentina/Buenos_Aires, UTC-3). 2. In Google Calendar, create a weekly recurring event (e.g. every Thursday at 12:00 local). 3. Edit the series with "This and following events" so the old series ends with UNTIL set to 02:59:59 UTC of the next day (= 23:59:59 local of the last valid occurrence day). 4. Sync with Odoo -> an extra event is created on the day after the last valid Thursday, which does not exist in Google Calendar. opw-6024835 Forward-Port-Of: odoo/odoo#273915 Forward-Port-Of: odoo/odoo#265297
Fixed an issue where a chatbot could crash if it tried to hand a visitor over to an operator, but no operators were configured for the live chat channel. Instead of showing an error, the chat now handles this case cleanly so the conversation can continue without interruption.
Original PR description
When a live chat channel has no operators configured and the chatbot script ends with a Forward to operator step, triggering that step causes a traceback. Steps to reproduce the error: - Install…
When a live chat channel has no operators configured and the chatbot script ends with a Forward to operator step, triggering that step causes a traceback. Steps to reproduce the error: - Install ``im_livechat`` module with demo data - Go to Live Chat > Configuration > Chatbots > Create a new chatbot > Add script > Step Type: Question > Set answers > Save > Add script > Step Type: Forward to operator > Only If: Set one of the above answers > Save - Go to Live chat > Channel > Click the configure channel on YourWebsite.com > Remove the operators > Save - Go to the chatbot > test > select the configured answer Traceback: ```py StopIteration ``` https://github.com/odoo/odoo/blob/8791cdcd89ea3cb56b1fac63b3e2ffbd2956a912/addons/im_livechat/controllers/chatbot.py#L65-L70 When the chatbot script reaches a Forward to operator step while no operator is configured in the live chat channel, no chatbot message is created. As a result, the generator iterates over an empty iterator, and the ``next()`` call raises a ``StopIteration`` exception, causing a traceback during the conversation. sentry-7435424405 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274384 Forward-Port-Of: odoo/odoo#261726
The attendance-based timesheet report now uses fully specified column names in its database query. This prevents the report from failing in customer databases that add their own fields with the same names, helping ensure the report opens reliably.
Original PR description
In `hr_timesheet_attendance_report`, the SQL query was using unqualified columns (e.g. `date` instead of `ts.date`)
It was not an issue in standard, but if a customer adds a `date` or `check_in` column to `hr_employee`, the query becomes ambiguous and fails.
To solve the issue, we explicitly qualify `ts.date` and `hr_attendance.check_in`.
upg-4445460
```python
File "/home/odoo/src/odoo/19.0/addons/hr_timesheet_attendance/report/hr_timesheet_attendance_report.py", line 24, in init
self.env.cr.execute("""CREATE OR REPLACE VIEW %s AS (
File "/home/odoo/src/odoo/19.0/odoo/sql_db.py", line 440, in execute
self._obj.execute(query, params)
psycopg2.errors.AmbiguousColumn: column reference "date" is ambiguous
LINE 44: AND date <= CURRENT_DATE
```
Forward-Port-Of: odoo/odoo#274341This update prevents URL autocomplete suggestions from spilling outside the screen on smaller devices. It improves the mobile editing experience by making the suggestion box fit the available width while still behaving normally on larger screens.
Original PR description
Step to reproduce: - Open Notes - Open the link popover - Type a URL in the URL input field Description of the issue/: - On mobile devices, URL autocomplete suggestions overflow the viewport. Cause: - The autocomplete suggestions container has a max-width of 600px. - On smaller screens, the container does not shrink to fit the available width, causing it to overflow the viewport. Solution: - Add width: 100% to the autocomplete suggestions container so it adapts to the available screen width on smaller devices while still respecting the existing max-width on larger screens. task-6201175 Forward-Port-Of: odoo/odoo#271925 Forward-Port-Of: odoo/odoo#269493
This change prevents a crash that could happen when users try to split a transfer that is already completed. In that situation, there is nothing left to split, so the system now safely does nothing instead of showing an error.
Original PR description
Issue before this commit: ========================= When splitting a done picking that contains at least one stock move whose done quantity is less than the demanded quantity (product_uom_qty), an…
Issue before this commit: ========================= When splitting a done picking that contains at least one stock move whose done quantity is less than the demanded quantity (product_uom_qty), an expected singleton traceback occurs. Steps to Reproduce: ========================= - Install the stock module with demo data. - Create a delivery picking for any product with a demand of 5. - Set the done quantity to 2. - Validate the picking without creating a backorder. - Try to split the validated/done picking. - An expected singleton traceback is raised. Cause of the issue: ========================= Previously, attempting to split a done picking simply returned because there was nothing left to split. After this [PR](https://github.com/odoo/odoo/pull/224952), the split action calls **message_post()** to post a note on the original picking of the generated backorder. However, no backorder is created when splitting a done picking since there is no remaining quantity to split. As a result, message_post() is called on an empty recordset, leading to an expected singleton traceback. With This Commit: ========================= Splitting a done picking has no functional purpose, as there is nothing left to split. In this case, simply return without performing any action. This preserves the previous behaviour and prevents the traceback.
This update ensures that certain Odoo modules are correctly licensed as LGPL-3, aligning with their community module status. Previously, these modules were incorrectly marked with an enterprise license. This change clarifies licensing and avoids potential legal issues.
Original PR description
Before this commit, the license set on manifest of some modules uses the enterprise license instead of `LGPL-3` license since it is a community module. This commit changes the license to set `LGPL-3`. Fixes #205134 Forward-Port-Of: odoo/odoo#274123 Forward-Port-Of: odoo/odoo#273597
This update fixes an issue where call controls were hidden behind the browser's URL bar on mobile devices. The change adjusts the overlay size to dynamically adapt to the visible viewport, ensuring call controls remain visible regardless of browser chrome. This improves the user experience when joining calls on mobile browsers.
Original PR description
Before this commit, joining a call in a mobile browser (Chrome, Safari, ...) would crop the bottom call controls (mic, camera, hang-up, ...) behind the browser's chrome (URL bar / bottom nav). On…
Before this commit, joining a call in a mobile browser (Chrome, Safari, ...) would crop the bottom call controls (mic, camera, hang-up, ...) behind the browser's chrome (URL bar / bottom nav). On mobile, entering the meeting uses the fullscreen overlay with `keepBrowserHeader: true`, so no native fullscreen is requested and the browser UI stays visible. The overlay was sized with the Bootstrap `vh-100` class (`height: 100vh`), and `100vh` resolves to the *large* viewport (as if the URL bar were hidden). Combined with `fixed-top`, the overlay extended past the visible area and pushed the control row off screen. This commit sizes the overlay with `100dvh` (dynamic viewport height) instead, which tracks the currently visible viewport and shrinks while the URL bar is shown, keeping the controls on screen. This is a no-op in native/desktop fullscreen where `dvh == vh`, and matches the `dvh` usage already present in the codebase (welcome page, bottom sheet). task-6353266 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update resolves an issue where inventory loss operations incorrectly opened a new scrap form instead of the associated picking. The fix ensures that when creating an inventory adjustment, the system now correctly directs users to the relevant picking, improving usability and accurate tracking of inventory loss. This change was made to align with the standard behavior of the system.
Original PR description
Currently, when the user manually creates an operation for inventory adjustment and then creates a picking for that operation, opening the move line for a product does not navigate to the…
Currently, when the user manually creates an operation for inventory adjustment and then creates a picking for that operation, opening the move line for a product does not navigate to the corresponding picking. Instead, it opens a new scrap form. ## Steps to replicate: - Install Inventory - Go to settings and Enable 'Storage Locations' - Create a product named 'Pen' with an on-hand quantity of 10. - Navigate to Inventory > Configurations > Locations - Create a new location: - Name: Office Supplies Consumption' - Location Type: Inventory Loss - Go to Configurations > Operation types > Create new operation type: - Name: Transfer to Office Consumption - Type of operation: Delivery - Sequence prefix: TOC - Source Location: 'WH/Stock' - Destination Location: Office Supplies Consumption - Create and validate a picking for 1 Pen using the operation type 'Transfer to Office Consumption'. - Open the 'Pen' product form. > In/Out smartbutton - Open the move line corresponding to the transfer created. ## Observed behavior: Instead of redirecting the user to the picking created for the office supply consumption operation, the system opens a new stock scrap form view. ## Root cause: This issue occurs when a user clicks the move line reference associated with a picking. In that case, `action_open_reference` is invoked on the stock move line, which subsequently calls the method with the same name on the related stock move at [1]. As a result, the scrap view is returned at [2]. This happens because the move is not marked as is_inventory, since the operation neither relocates quants nor manually adjusts on-hand quantities and the destination location still uses the Inventory Loss / Inventory usage type. Since the move is not linked to any scrap record, its `scrap_id` is empty. Consequently, the method returns an empty scrap form, which causes the issue. **Why did this not occur in earlier versions?** Prior to this [commit](https://github.com/odoo/odoo/commit/53181c7ac4d940d889370da61d39150560cdb0d8 ), the `scrap_location` field existed. After its removal, the logic was changed to rely on locations of type Inventory Loss, effectively causing all inventory loss locations to be treated as scrap locations. Before this change, the condition depended on the scrapped boolean [3], which was only set for actual scrap locations. Because not all inventory loss locations were considered scrap locations, the system would fall back to opening the picking form as the reference, avoiding this issue. **Why does the issue not occur in 19.2+?** The issue no longer occurs in 19.2+ because the `stock.scrap` model was removed and the scrap-related logic was moved to stock.move. As part of this [commit](https://github.com/odoo/odoo/commit/1c7d80a10b5d7db1c4163166bf52b3f3c77044ba ), the code path that returned the stock scrap view was removed. The system now falls back to the picking view instead, as shown at [4]. [1]- https://github.com/odoo/odoo/blob/65937b5cdc6c638a9e9ff7085cbab1567ca24142/addons/stock/models/stock_move_line.py#L1030 [2]- https://github.com/odoo/odoo/blob/65937b5cdc6c638a9e9ff7085cbab1567ca24142/addons/stock/models/stock_move.py#L2584-L2594 [3]- https://github.com/odoo/odoo/blob/24f829cd8de3d97d6ed414e179f9903e3f8e7b70/addons/stock/models/stock_move.py#L2542-L2552 [4]- https://github.com/odoo/odoo/blob/90769e7f74b4d8e86e5bbc2e4403ed4cd0c09ae6/addons/stock/models/stock_move.py#L2609-L2627 ## Solution: Tighten the condition for inventory loss operations so that the scrap view is only returned when the move is actually linked to a scrap record (`scrap_id`). Otherwise, the method should fall back to opening the source picking, matching the behavior of both earlier and later versions. This distinction is important because an inventory loss location is not necessarily used for scrapping. As demonstrated in the reproduction steps, such locations can also be used to track other forms of inventory loss, such as distributing office supplies to employees. Creating dedicated inventory loss locations allows users to categorize and account for different types of losses more accurately. In these cases, opening the picking that generated the inventory loss provides a more meaningful reference to the user than displaying a new, empty scrap form. opw-6270679 Forward-Port-Of: odoo/odoo#270563
This update corrects a bug where scrapping a component during a manufacturing order would still allow the same serial number to be used, leading to incorrect inventory counts. The fix ensures that scrapped components are properly 'unpicked,' allowing the system to automatically reserve the next available serial number and maintain accurate inventory data. This improves the reliability of manufacturing processes.
Original PR description
Currently, when the user scraps a component during a manufacturing order, the system can still consume the same lot/serial number during production, leading to double consumption even when the…
Currently, when the user scraps a component during a manufacturing order, the system can still consume the same lot/serial number during production, leading to double consumption even when the product is no longer available in inventory. ## Steps to produce: - Install the Manufacturing app. - Enable 'Work Orders' and 'Lots & Serial Numbers' from the settings. - Create two products: 'Car' and 'Engine'. - Configure 'Engine' to be tracked by 'Serial Number' and update its on-hand quantity to 2 using two different serial numbers. - Create a Bill of Materials (BoM) for 'Car' with 'Engine' as a component. - Create a work center named 'Car Assembly'. - Go to Manufacturing > Configuration > Operations. - Create a new manufacturing operation named 'Engine Insertion' with: - Bill of Materials: 'Car' - Work Center: 'Car Assembly' - Create and confirm a new Manufacturing Order (MO) for 'Car'. - Open the related work order and start the operation. - From Actions > Scrap, scrap the 'Engine' serial number currently reserved for the MO. - Click Produce All. - Open the product view for 'Engine' and check the on-hand quantity. ## Observed behavior: Even after the user scraps the product during the work order, the system still allows the same serial-numbered component to be consumed during production. This results in negative on-hand quantities and creates inconsistencies in inventory and manufacturing data. ## Root cause: When the user starts the work order, the `button_start` function [1] is called. This sets the `qty_producing` field, which triggers its inverse method `_set_qty_producing`. As part of this flow, the component move is marked as picked at [2]. This, in turn, triggers the inverse method of the `picked` field, which marks all move lines in the move as picked, as shown at [3]. Later, when the user scraps the same serial-numbered product, the `do_scrap` function is called. This invokes `_action_done` at [4], which further calls `_action_done` on the move lines at [5]. During this process, `_free_reservation` is executed at [6]. However, because the move lines were previously marked as picked, they no longer satisfy the domain condition at [7]. As a result, they are not unlinked at [8]. This leaves the reservation intact and eventually causes the scrapped component to still be consumed when the user produces the quantity on the manufacturing order. **Why does this issue not occur in saas-19.3?** This issue no longer occurs in saas-19.3 after this [commit](https://github.com/odoo/odoo/commit/bb56600bfc81b9a6573a867df93a706de8154d0a), which removed the manual consumption field. As a consequence, move lines are no longer marked as picked when starting work orders, preventing the inconsistent state that leads to this issue. [1]: https://github.com/odoo/odoo/blob/8f5d7b5cd0c3e1808375baef8f0834d3f2e27a75/addons/mrp/models/mrp_workorder.py#L659-L660 [2]: https://github.com/odoo/odoo/blob/8f5d7b5cd0c3e1808375baef8f0834d3f2e27a75/addons/mrp/models/mrp_production.py#L1417-L1421 [3]: https://github.com/odoo/odoo/blob/8f5d7b5cd0c3e1808375baef8f0834d3f2e27a75/addons/stock/models/stock_move.py#L287-L290 [4]: https://github.com/odoo/odoo/blob/8f5d7b5cd0c3e1808375baef8f0834d3f2e27a75/addons/stock/models/stock_scrap.py#L152-L158 [5]: https://github.com/odoo/odoo/blob/8f5d7b5cd0c3e1808375baef8f0834d3f2e27a75/addons/stock/models/stock_move.py#L2125 [6]: https://github.com/odoo/odoo/blob/8f5d7b5cd0c3e1808375baef8f0834d3f2e27a75/addons/stock/models/stock_move_line.py#L696-L700 [7]: https://github.com/odoo/odoo/blob/8f5d7b5cd0c3e1808375baef8f0834d3f2e27a75/addons/stock/models/stock_move_line.py#L807-L817 [8]: https://github.com/odoo/odoo/blob/8f5d7b5cd0c3e1808375baef8f0834d3f2e27a75/addons/stock/models/stock_move_line.py#L851 ## Solution: When a component move line is scrapped, it should be unpicked so that the system can reserve the next available lot/serial number automatically. Once a component has been physically scrapped, it no longer makes sense to keep it marked as picked and reserved. Doing so leaves the MO in an inconsistent state, where the system still considers the scrapped component usable. By unpicking the move line after scrapping, both the system and the user clearly see that there is no longer any reserved quantity associated with that component. This also allows system to automatically pick from next available lot or serial number, ensuring the manufacturing process can continue smoothly. Such behavior is especially important in shop floor scenarios, where mistakes or damages may occur after components have already been registered, and the manufacturing process should continue without interruption. opw-6157406 Forward-Port-Of: odoo/odoo#264589
This update fixes an issue where the change amount displayed in the Point of Sale UI was incorrectly shown as a positive value. Now, change amounts (refunds) are accurately displayed as negative numbers, ensuring accurate financial reporting and a better user experience when processing refunds. The change ensures correct calculations and prevents discrepancies in transactions.
Original PR description
Steps to Reproduce ------------------------ - Install point of sale. - Do a order and pay more than the amount. Issue ------ - The change amount is displayed as a positive value on the UI. - Typically, amounts going out of the shop (like change given to the customer) should be shown as negative. Cause ------- - The change amount was not correctly represented in the UI. - Since the change flows in the opposite direction of the payment, it should be displayed as the negation of the original amount. FIX ----- - Updated the frontend to display the change amount with the correct (negative) sign. - No backend changes were required, as the correct value was already being handled during order synchronization Enterprise PR: https://github.com/odoo/enterprise/pull/112560 task: 6074620 Forward-Port-Of: odoo/odoo#263606 Forward-Port-Of: odoo/odoo#256776