Thursday, September 3, 2026
46 changes · saas-19.4
Resolved issues and error corrections
Fixes an issue where manually increasing the quantity on a timesheet invoice could prevent later timesheet periods from being invoiced. Businesses can now bill future logged work correctly while preserving refund handling for timesheet invoices.
Original PR description
## Issue When a use rmanually increases the invoiced quantity on a timesheet invoice, subsequent timesheets logged in future periods can no longer be invoiced. The system assumes that the most recent…
## Issue
When a use rmanually increases the invoiced quantity on a timesheet invoice, subsequent timesheets logged in future periods can no longer be invoiced. The system assumes that the most recent logged hours are already covered by the previously over-invoiced amount, blocking the billing of the most recent timesheet entries.
## Steps to reproduce
1. Install *Sales Timesheet* (`sale_timesheet`)
2. Create a Product P
- Product Type: Service
- Invoicing Policy: Based on Timesheets
- Create on Order: (Project &) Task
3. Create an SO:
- Customer: Any
- Product: P (any quantity)
- Confirm
4. Record hours on the task created:
- 06/01/2026 (June 1st): 1 hour
- 07/01/2026 (July 1st): 1 hour
5. Create the invoice for the June timesheet entry (by setting a timesheets period when creating the invoice), then **change the quantity to any value strictly greater than 2** and confirm.
6. Create the invoice for July
7. **An "Invalid Operation" error appears, stating that there's nothing to invoice, even though the timesheet entry from July was never invoiced.**
## Cause
Since https://github.com/odoo/odoo/commit/3b86ac3d180993239b63fd305ee0ba1f17f7eb20, the computation of the quantity to invoice changed to include the difference between the quantity delivered and the quantity already invoiced. In the flow described by the steps to reproduce above, the quantity to invoice is larger than the quantity delivered, making the `qty_to_invoice` equal to `0.0`.
https://github.com/odoo/odoo/blob/626d31fa0191bfe7ca8e1fcf177357eeeb60f2c7/addons/sale_timesheet/models/sale_order.py#L331-L334
The reason for the fix above being the partial refunding of timesheet-related invoices, we can keep that solution when working with refunded invoices, and keep the previous behavior for other cases.
This solution solves the issue in the steps to reproduce above, but was also manually tested on the issues from https://github.com/odoo/odoo/commit/3b86ac3d180993239b63fd305ee0ba1f17f7eb20 and https://github.com/odoo/odoo/commit/64cf4afabd0c5ef040cf87fc6f3125fe0bb81bbb.
opw-6485674
Forward-Port-Of: odoo/odoo#286301
Forward-Port-Of: odoo/odoo#284470This fix prevents the mail reply suggestion list from reopening after a user has dismissed it with Escape. It makes the reply discard flow more reliable and avoids intermittent failures caused by delayed server suggestions.
Original PR description
Two independent causes made "reply: discard on pressing escape" red, one commit each. "[FIX] mail: wait for the mention suggestions before Escape" is the one that fixes the reported failure, and it holds on every branch: the test presses Escape while the mention fetch is in flight, and the suggestions arriving from the server re-open the list that Escape closed, so the re-opened list takes the second Escape and the reply is never discarded. The test now waits for the fetched suggestions before pressing Escape. "[FIX] mail: keep the suggestion list closed on a re-render" backports "[FIX] mail: keep composer suggestion list closed on unrelated re-render", which entered at 19.0 and never came down. Here NavigableList is re-opened on every patch, so opening the emoji picker after Escape brings the dismissed list back, and it then steals the Escape meant for the picker. https://runbot.odoo.com/odoo/error/946314 Forward-Port-Of: odoo/odoo#286041 Forward-Port-Of: odoo/odoo#284725
Accounting users can now generate BOE files for Spain's Modelo 115 tax report without needing company access-rights permissions. This removes an unnecessary access error caused by the export wizard trying to save company information that was not actually being changed.
Original PR description
Users who only have accounting rights (not the Settings > Users Companies > Access Rights group) get an access error on the Companies model when generating the BOE file for the Modelo 115 tax…
Users who only have accounting rights (not the Settings > Users Companies > Access Rights group) get an access error on the Companies model when generating the BOE file for the Modelo 115 tax reports, even though exporting a BOE file has nothing to do with editing company configuration and should be available to any accountant. Steps to reproduce: ------------------- * Log in as a user with accounting rights only (not part of the Companies > Access Rights group) * Go to Accounting > Reporting > Tax Return, open the Mod 115 report * Click the gear icon > BOE > Generate BOE > Observation: An AccessError is raised: "You are not allowed to modify 'Companies' (res.company) ... This operation is allowed for the following groups: Access Rights", even though the user is not trying to edit the company. Why the fix: ------------ The BOE wizard shared by Mod 111/115/303 declares a `company_partner_id` field, related to `company_id.partner_id`, with `readonly=False`. That field is invisible in every view and only exists to compute the domain of `partner_bank_id`; it was never meant to be edited by the user. Because it is declared writable, the ORM attaches an inverse to the related field, so saving the wizard (which happens when generating the BOE, since the field, though invisible, is still part of the view and thus of the saved values) writes `company.partner_id` back onto `res.company`, even though the value never actually changes. That implicit write requires write access on res.company, which is only granted to the Access Rights group, causing the error for regular accountants. Dropping `readonly=False` keeps the field as a plain readonly related field, still usable for the bank account domain, without ever triggering that spurious write. opw-6388869 Forward-Port-Of: odoo/enterprise#130058 Forward-Port-Of: odoo/enterprise#126661
Users who type a date or date and time manually and press Enter will now have that value saved correctly. This prevents lost changes in forms when users navigate by keyboard instead of opening the calendar picker.
Original PR description
Example of steps: - open any form view with a date field - navigate to this date field with tab - For example clicking on the previous field and pressing tab - type another date press enter (without…
Example of steps: - open any form view with a date field - navigate to this date field with tab - For example clicking on the previous field and pressing tab - type another date press enter (without opening the picker) - save => The change has not been saved. `onInputKeydown` closes the picker on Escape and on Enter the same way: by calling `saveAndClose()` directly, without first calling `updateValueFromInputs()` to parse the raw text typed in the input into the reactive `pickerProps.value`. This doesn't work when the calendar popover was never opened (i.e. the value was typed by hand instead of picked visually), `saveAndClose()` calls `apply()` directly, which only pushes `pickerProps.value` to `onApply`. Since that value was never refreshed from the input's text, `apply()` sees no change and silently returns without calling `onApply`, so the typed value is lost. Every other confirmation path (`onInputChange`, the popover's `onClose`, and `Ctrl+Enter`) already calls `updateValueFromInputs()` before proceeding, so plain Enter was the only path missing it. To fix this we call `updateValueFromInputs()` before `saveAndClose()` in the Enter/Escape case, like every other confirmation path already does. opw-6511435 Forward-Port-Of: odoo/odoo#285963
The SMS mass mailing module now recognizes a newly added SMS failure reason. This prevents certain mailing flows from crashing when that specific delivery error occurs, improving reliability for SMS campaigns.
Original PR description
This commit fixes an issue with the addition of a new failure_type in the SMS module via [1]. The corresponding failure_type wasn't added in mass_mailing_sms meaning that some flows could crash if the specific error was set. Now, the new failure_type is added to the module. [1]:https://github.com/odoo/odoo/commit/06bab9a82dae911c26fd5dd329cb43a466d13569
The point of sale product information popup now shows accurate tax details for combo products. This helps staff and customers see the right minimum combo price and tax information, even when combo choices have no included item.
Original PR description
Product info popup was not showing the correct tax details for combo products. This commit fixes the issue. The popup display now the minimal price of a combo with an item selected for each combo choice; even if the combo choice isn't including any item. Forward-Port-Of: odoo/odoo#285169 Forward-Port-Of: odoo/odoo#282870
Invoices created from point-of-sale orders linked to sales orders now keep the customer's original reference from the sales order. This improves invoice clarity and customer traceability, especially when multiple orders are consolidated.
Original PR description
The pos_sale override of _prepare_invoice_vals left ref and invoice_origin untouched, so the SO's client_order_ref was lost on the invoice. The fix is to mirror sale.order._prepare_invoice and set both fields from the linked SO, while preserving pos_reference traceability for mixed consolidated batches. task-id: 6295629 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278035
Fixes an issue where selected website themes could install without applying key visual changes like headers and footers. This ensures businesses get the expected website appearance immediately after choosing a theme, reducing setup confusion and manual fixes.
Original PR description
--- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286221 Forward-Port-Of: odoo/odoo#283174
Helpdesk SLA analysis now shows the actual time a ticket stayed open, from creation to closing, instead of stopping at assignment. This aligns SLA reporting with ticket analysis and gives managers a more accurate view of resolution time.
Original PR description
1. Open Helpdesk > Tickets and create a ticket on the team "Customer Care", assigned to yourself 2. More than an hour later, move it to the "Solved" stage to close it 3. Open Helpdesk > Reporting > Ticket Analysis, switch to the pivot view and pick the "Hours Open" measure -> the ticket holds the hour it stayed open 4. Open Helpdesk > Reporting > SLA Status Analysis and pick the "Hours Open" measure as well -> the ticket holds nothing, as it was assigned as soon as it was created odoo/enterprise#47454 added the "Hours Open" measure of the ticket analysis to the SLA status analysis, but computes it up to the assignment date instead of the closing date. The measure therefore holds the hours until the ticket was assigned, which the report already offers as "Working Hours to Assign". With this commit, both reports count the hours from the creation of the ticket to its closing. Forward-Port-Of: odoo/enterprise#130170
Completed field service shifts linked to sales orders now keep their planned hours instead of being reset to zero. This prevents sold service time from incorrectly appearing as still needing to be planned, giving teams a more accurate view of scheduled work.
Original PR description
## before: When marking a shift linked to SO as complete. The `allocated_hours` of this shift is reset to 0. So when the `Planned` button tries to compute the `planning_hours_planned` it adds zero to the planned hours, making all the hours go to the `To Plan`, which is incorrect ## after: prevents the `allocated_hours` from being recomputed when making the shift as complete to avoid this issue. This will leave the hours to be calculated in the `Planned` stat button instead --- task-6425357 Forward-Port-Of: odoo/enterprise#126396
This fix ensures the point of sale keeps the selected receipt printer available after a refresh, so cash drawers connected to printers can open as expected. It also prompts staff to choose a default printer when needed, reducing silent failures at checkout.
Original PR description
Steps to reproduce: - Set only one printer with cashdrawer - Open PoS - Try to open the casdrawer => Silently won't open Issue: defaultPrinter was only saved in localstorage when various printer was set on the config. Fix: Now the printer is always saved in the localstorage so that when the pos is refresh, defaultPrinter is always set. Also when trying to open the cashdrawer if various printer are set in the config, make sure that the select default printer popup is shown. Task-6519466 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fix prevents users from deleting the image inside a website card while leaving behind an empty cover area. It avoids confusing editing behavior and prevents an error that could occur when using the Cover Image options.
Original PR description
It was possible to remove the image inside a card cover while keeping the figure wrapper. The card option would then still consider that there was a cover image even though the image was gone, which could also lead to a traceback. Steps to reproduce: - Insert the `s_three_columns` snippet - Click on the image of one card - Either press "Enter", "Delete", "Backspace" - Hover the "Cover Image" options => The image is removed but the `<figure>` is still there, so the option is still considered active (leading to a traceback) task-6081728 Forward-Port-Of: odoo/odoo#285131 Forward-Port-Of: odoo/odoo#280086
Users can no longer create Odoo boxes directly from printer settings. This helps ensure each box is properly paired with a real physical device, reducing setup mistakes and unreliable point-of-sale self-order configurations.
Original PR description
We prevent users from creating oboxes from pos.printer model, as oboxes should be paired with an actual device. Forward-Port-Of: odoo/enterprise#130051 Forward-Port-Of: odoo/enterprise#129960
The return creation wizard now checks for existing returns only within the selected company. This prevents users working with multiple active companies from being incorrectly blocked by returns that belong to another company.
Original PR description
To reproduce the issue: 1) Create two companies in Belgium: A and B 2) Manually create a return for A before its opening date 3) Switch to company B, and keep A active as well 4) Try creating a return of the same type and at the same date as in 2) ===> The wizard blocks you and displays a warning saying there's already a return at this date. There is, but for another company. We fix that by properly filtering the company when searching for existing returns. Moving the _read_group inside the loop on self is okay here: we'll never compute that field for multiple wizards at once. Forward-Port-Of: odoo/enterprise#130303
The website builder no longer shows an unreliable live preview for header width changes on header designs that cannot support it. This prevents misleading previews and helps users apply header layout changes with more predictable results.
Original PR description
The header width option is not previewed properly on the following header templates: - `template_header_boxed` - `template_header_sales_one` - `template_header_sales_two` - `template_header_sales_three` - `template_header_sales_four` - `template_header_search` This happens because these templates are not compatible with the action `previewableWebsiteConfig` (their width can't be previewed by adding a single class). This commit fixes the problem by using the action `websiteConfig` instead of `previewableWebsiteConfig` when one of these templates is set. task-6420611 Forward-Port-Of: odoo/odoo#286292 Forward-Port-Of: odoo/odoo#282311
The website editor now keeps resize and selection controls visible even when an animated page element overlaps the side panel. This makes it easier for users to resize and understand the position of animated content while editing pages.
Original PR description
Steps to reproduce: - Drop a few snippets to make the page scrollable - At the bottom, drop the `s_three_columns` snippet - Click on the last Card - Add an animation "onScroll" (Effect - Slide, Intensity - 100) - Scroll top slightly to hide a part of the card behind the sidebar => The resize overlay is partially hidden The elements `.hb-row` have a z-index of 2, so they appear in front of the overlay which has a z-index of 1. It was decided to fully show the overlay to allow resizing. Keeping the overlay visible in front of the sidebar also allow the user to see where animated element is. task-6476269 Forward-Port-Of: odoo/odoo#283842 Forward-Port-Of: odoo/odoo#282796
Analytic plan applicability now respects the default setting in screens that do not provide a business context, such as Work Centers or Employee views. This prevents company-specific invoice rules from incorrectly making analytic distribution mandatory in unrelated areas.
Original PR description
### Issue: When an analytic plan has applicability lines with a company filter, the applicability is incorrectly applied on views that do not define a `business_domain`, such as Work Centers or…
### Issue: When an analytic plan has applicability lines with a company filter, the applicability is incorrectly applied on views that do not define a `business_domain`, such as Work Centers or Employee views For example, if a plan has: - Default Applicability: Unavailable - A line with Domain: Invoice, Company: My Company, Applicability: Mandatory Opening the analytic distribution on a Work Center shows `Mandatory` instead of the default `Unavailable` ### Cause: In commit https://github.com/odoo/odoo/commit/ffcf2ee1a3185ef73db93bfd95625844506692c5 `_get_score` was updated to return `0.5` when the applicability line's company matches the caller's company, even when no `business_domain` is provided In `_get_applicability`, the loop selects the first rule whose score exceeds the current minimum, which starts at `0`: https://github.com/odoo/odoo/blob/710e056e5171af2ab72d7d7793da3518f12faf5e/addons/analytic/models/analytic_plan.py#L255-L264 A score of `0.5` is enough to win over the default applicability, so a company-only match on a domain-specific rule incorrectly overrides the default when no `business_domain` is passed ### Steps to reproduce: - Install `mrp` and `accountant` with demo data - Enable Analytic Accounting in Settings - Open the Internal analytic plan and edit its applicability line: -- Remove the account prefix -- Default Applicability: Unavailable -- Domain: Invoice, Company: My Company (SF), Applicability: Mandatory - Go to Manufacturing > Configuration > Work Centers - Open any work center and click on Analytic Distribution Before the fix, Internal is shown as Mandatory instead of Unavailable Removing the company from the applicability line confirms the issue opw-6404884 Forward-Port-Of: odoo/odoo#280312
Links added in Manufacturing Order notes now open in a new browser tab from the Shop Floor, instead of interrupting the operator's current screen or opening the note editor. This keeps users in their workflow while still giving quick access to linked documents.
Original PR description
Steps to reproduce 1. On a Manufacturing Order, open the Miscellaneous tab, click in Additional Notes, type "/file", pick "File" (Insert a file from Documents), select a document and save. 2. Open…
Steps to reproduce 1. On a Manufacturing Order, open the Miscellaneous tab, click in Additional Notes, type "/file", pick "File" (Insert a file from Documents), select a document and save. 2. Open the Shop Floor of that Manufacturing Order. 3. On the order card, click the link shown in the note. Expected: the link opens in a new tab. Actual: the Notes edition dialog opens and the link is not opened. Issue --- On the Shop Floor the Additional Notes HTML field is rendered inside a container whose click handler opens the note edition dialog, its links carry no target and the handler stops the event propagation, so clicking a link opens the edition dialog instead of the linked document. Additional Notes became an HTML field in ebc30649c0f5, which allowed such links while this rendering was never adapted to open them. https://github.com/odoo/enterprise/blob/bfda5100ddd423f9e5fb91a9f83b4719c1f58397/mrp_workorder/static/src/mrp_display/mrp_display_record.xml#L58-L63 The note links now receive target="_blank" after mount and on every patch so they open in a new tab like the readonly HTML field viewer, and the container handler ignores clicks landing on a link so it no longer opens the edition dialog for them. https://github.com/odoo/enterprise/blob/bfda5100ddd423f9e5fb91a9f83b4719c1f58397/mrp_workorder/static/src/mrp_display/mrp_display_record.js#L106-L111 opw-6487702
This fixes an issue where pickup point search could fail to load when a delivery address included a country. Customers should now see available pickup locations more reliably during checkout, reducing confusion and blocked deliveries.
Original PR description
`country_id` is a number so the fix in #281720 - which avoids a traceback when no country is present - now leads to nothing being loaded when the delivery address has a country. Because `country_id?.id` now gives `undefined`. The fix makes sense only if the field is marked as a many2One as done in 319bb52 (which was only merged in 19.4+). This is consistent with fix edf65dc done in 19.4+ as well. Forward-Port-Of: odoo/odoo#285006
Users requesting a French PDP migration now see a consistent message instead of misleading timing such as availability tomorrow. This avoids confusion by making the migration status communication clearer until more precise client-side tracking is available.
Original PR description
Currently when the user requested a migration, we don't show it in any way to the user, and the only timeline we give ("available tomorrow") is completely false. Because we don't have any field we could use for this client-side (maybe from 19.3 we can use the catch-all-json field) So just make the message same for everybody.
no-task
Forward-Port-Of: odoo/odoo#283702
Forward-Port-Of: odoo/odoo#283594Manufacturing orders that were split, merged, and later adjusted could incorrectly produce double the intended quantity or fail during valuation. This fix ensures the produced quantity and product costing are handled correctly when an order has multiple finished product lines.
Original PR description
When the quantity of a make-to-order manufacturing order is changed, its finished move is copied to propagate the extra quantity downstream. In some cases (after splitting then merging back…
When the quantity of a make-to-order manufacturing order is changed, its finished move is copied to propagate the extra quantity downstream. In some cases (after splitting then merging back productions) that copy is not merged back, so the order ends up with two finished moves for the same product. On validation, two things then go wrong: - _post_inventory writes the produced quantity on each finished move, so both get the full quantity and the production is doubled - mrp_account._cal_price prices the finished move and calls ensure_one(), which raises "Expected singleton" for an average/fifo product, so "Produce All" fails Split the produced quantity across the finished moves with unit_factor (like _set_qty_producing already does), and price them as a whole instead of expecting a single finished move. Steps to reproduce: - Create a BoM for product A with the MTO route, and a component B - Create a Sale Order for 30 units of A, confirm it - Split the MO into 3 productions of 10, merge two of them - On the third, Update Quantity 10 -> 15, then Produce All - The product should be produced once (15, not 30), with A valued in average/fifo it instead of an error. opw-6242504 opw-6310972 opw-6307025 opw-6354739 Forward-Port-Of: odoo/odoo#286173 Forward-Port-Of: odoo/odoo#269254
This fixes an issue where delivery order lines could recalculate their unit of measure at creation time, leading to incorrect price totals in some sales orders. By keeping the intended unit of measure, shipping line amounts remain consistent and reliable when delivery charges are added.
Original PR description
In this PR, https://github.com/odoo/odoo/pull/186250, the `product_uom` field was renamed to `product_uom_id`. However, in the `delivery` module, `product_uom_id` is dropped from the values when the…
In this PR, https://github.com/odoo/odoo/pull/186250, the `product_uom` field was renamed to `product_uom_id`. However, in the `delivery` module, `product_uom_id` is dropped from the values when the delivery line is created. This causes `product_uom_id` to be recomputed. This commit reintroduces `product_uom_id` in the values to prevent the field from being recomputed. **Description of the issue/feature this PR addresses:** For a strange reason, when a module inherits from `sale.order.line` and adds some computed fields with `precompute=True`. `price_unit`, `price_subtotal`, and `price_total` are computed incorrectly. I have attached a module to demonstrate the issue. https://github.com/user-attachments/assets/ebdd8695-c9d8-477b-b5cf-ba6d8d41e84a Without this change, the test fails, and Odoo incorrectly recomputes the fields, as shown in the video. <img width="1232" height="515" alt="image" src="https://github.com/user-attachments/assets/27370f1f-e7b7-4102-a606-0181b9d1a97a" /> When the ORM computes fields marked as `precompute=True`, in this function `_add_precomputed_values` https://github.com/odoo/odoo/blob/0d44f26d9b0fb1c1a5db463cf1f8dd0d3c72ba26/odoo/orm/models.py#L4836, `price_unit` is 0, but the records get `price_unit` from the product. Therefore, when [_compute_amount](https://github.com/odoo/odoo/blob/0d44f26d9b0fb1c1a5db463cf1f8dd0d3c72ba26/addons/sale/models/sale_order_line.py#L855) is called, the values are computed with an incorrect `price_unit`. <img width="1087" height="940" alt="image" src="https://github.com/user-attachments/assets/92feadf0-7f93-4acc-8f1a-931db0655fcc" /> **Steps to reproduce the issue:** - Install the attached module. [sale_precompute.zip](https://github.com/user-attachments/files/31265993/sale_precompute.zip) - Configure a delivery carrier as free for orders over 1, and set the fixed price to 5, for example. - Create a sales order and add a product with a value greater than 1. - Add the shipping method. The price should be 0. In the sales order line, `price_unit` is 0, but `price_subtotal` and `price_total` are equal to 5 (the product's sale price). For more context, this module is a simple example extracted from the OCA `product_secondary_unit` module, which adds a mixin with these fields: https://github.com/OCA/product-attribute/blob/18.0/product_secondary_unit/models/product_secondary_unit_mixin.py. In the `sale_order_secondary_unit` module, `sale.order.line` inherits from this mixin. You can see the error in this PR: https://github.com/OCA/sale-workflow/pull/4535. https://github.com/OCA/sale-workflow/actions/runs/32259842816/job/96090194021?pr=4535#step:8:509 I understand that this requires a deeper investigation into precompute to solve the underlying issue, but I propose setting `product_uom_id` in the `_prepare_delivery_line_vals` method as a temporary solution while the final solution is being investigated. I understand that this field should not have been removed from `_prepare_delivery_line_vals`; the referenced PR only renamed the field and did not intend to remove the value from this method. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284316 Forward-Port-Of: odoo/odoo#283551
VoIP call records in Odoo now show the correct outcome when a call is answered or rejected in another phone application such as Linphone. This prevents calls from incorrectly appearing as missed or remaining stuck in progress, giving users more accurate call history when Odoo is open alongside external VoIP tools.
Original PR description
Steps to reproduce: - Have an external VoIP software configured (e.g. Linphone) - Have your Odoo configured and opened too - Call your VoIP number, using your smartphone => Both the softphone and…
Steps to reproduce: - Have an external VoIP software configured (e.g. Linphone) - Have your Odoo configured and opened too - Call your VoIP number, using your smartphone => Both the softphone and Linphone ring - Answer or reject using Linphone => The VoIP call record in Odoo immediately switches from "Trying to call" to "Missed". While there was no guarantee for our VoIP integration to work alongside Linphone in 19.0, we decided this should be an easy safe enough fix. Starting 19.2 (with [1]), the fix will be simplified and hopefully prettier thanks to the ameliorations that were made. After this fix, provided Odoo is open while Linphone is used, the call records will now switch to the right terminated / rejected status, still immediately once Linphone answers / rejects. In future versions and especially 20.0+, the system will be different and will allow way more features like this one to work better (e.g. here the call record only even exists if Odoo is opened while using Linphone and we won't have any information about the call duration). [1]: https://github.com/odoo/enterprise/commit/942f32316ab02d8c739fe7fdd5ec2bdde472a68e task-6449259 Forward-Port-Of: odoo/enterprise#130047 Forward-Port-Of: odoo/enterprise#127077
Fixes an issue that could prevent Swiss payslip payment reports from being generated when employees use Revolut bank accounts. This keeps payroll payment processing reliable after recent bank data changes in Odoo.
Original PR description
res.bank and res.partner.bank.bank_id were removed in saas-19.2: the bank's identity now lives directly on the bank account as bank_bic and bank_name. The Revolut detection added in fba51a6a77a still read bank_account.bank_id, raising an AttributeError when generating the ISO20022 payment report for Swiss payslips. Forward-Port-Of: odoo/enterprise#129915 Forward-Port-Of: odoo/enterprise#129156
The project forecasting tool now schedules work correctly when several roles are involved. This helps teams get more reliable automatic planning results and reduces the need for manual adjustments.
Original PR description
task-6484707 Forward-Port-Of: odoo/enterprise#129246 Forward-Port-Of: odoo/enterprise#128541
Manufacturing orders no longer show an incorrect consumption warning when a serial-tracked purchased component is received after the finished product serial number is assigned. This prevents unnecessary user confusion and lets valid production flows complete without misleading alerts.
Original PR description
Steps to reproduce the bug: - Warehouse configured for 2-Step Manufacturing - Component "C1": - Routes: MTO + Buy - Tracking: By Unique Serial Number - Create a Finished product: - Route: Manufacture…
Steps to reproduce the bug:
- Warehouse configured for 2-Step Manufacturing
- Component "C1":
- Routes: MTO + Buy
- Tracking: By Unique Serial Number
- Create a Finished product:
- Route: Manufacture
- Tracking: By Unique Serial Number
- BoM:
- component "C1": 1 unit
- Create and confirm the Manufacturing Order
- Generate/assign the serial number for the finished product immediately, before the related purchase order is even confirmed
- Confirm the Purchase Order
- Receive the component
- Transfer the component to WH/Pre-Production
- Click Produce All
Problem:
A Consumption Warning was displayed stating that the consumed quantity differs from the expected quantity, even though the consumed quantity was exactly equal to the BoM quantity and no manual quantity change was performed. Clicking "Set Quantities & Validate" completed the MO successfully, hiding the inconsistency.
`_get_consumption_issues()` only counts a raw move's quantity as "consumed" when `move.picked` is `True`
[(odoo/addons/mrp/models/mrp_production.py#L1791)](https://github.com/odoo/odoo/blob/19.0/addons/mrp/models/mrp_production.py#L1791).
Generating the finished product's serial number calls `_set_qty_producing()`
[(odoo/addons/mrp/models/mrp_production.py#L1402)](https://github.com/odoo/odoo/blob/19.0/addons/mrp/models/mrp_production.py#L1402).
, which itself only sets `move.picked = True` when `move.quantity` is truthy
[(odoo/addons/mrp/models/mrp_production.py#L1443)](https://github.com/odoo/odoo/blob/19.0/addons/mrp/models/mrp_production.py#L1443).
At that point the MTO component had not been received yet, so `move.quantity` was still 0 and `picked` was never set. Once the component was later received and transferred to Pre-Production, `_action_assign()` correctly reserved the raw move (`quantity` became correct), but nothing ever went back to flip `picked` to `True`, since `_set_quantities()`
[(odoo/addons/mrp/models/mrp_production.py#L2932)](https://github.com/odoo/odoo/blob/19.0/addons/mrp/models/mrp_production.py#L2932).
only calls `_set_qty_producing()` again when `qty_producing` is still falsy, which was no longer the case. `_get_consumption_issues()` therefore still counted the consumed quantity as 0 against the expected BoM quantity.
Solution:
In `pre_button_mark_done()`, for auto productions (single unit being produced), after `_set_quantities()` runs, also mark as `picked` any non-manual-consumption raw move that is not yet `picked` but whose reserved `quantity` already exactly matches its own `product_uom_qty`. This is scoped to auto productions only, since on a multi-unit production a raw move's aggregate `quantity` can equal its `product_uom_qty` by coincidence (reservation for future backorder steps) even though only part of it is meant to be consumed for the current step.
opw-6421531
Forward-Port-Of: odoo/odoo#285405
Forward-Port-Of: odoo/odoo#281258Fixes the DIN5008 invoice layout so addresses align correctly when invoices are sent by post through Snailmail. This ensures German customer invoices fit expected postal window positioning without changing the regular invoice layout.
Original PR description
**Steps to reproduce:** - Install l10n_din5008 and Accounting. - Enable Snailmail from Accounting → Settings. - Create a German customer (Fiscal Country: Germany). - Create and post a customer…
**Steps to reproduce:** - Install l10n_din5008 and Accounting. - Enable Snailmail from Accounting → Settings. - Create a German customer (Fiscal Country: Germany). - Create and post a customer invoice using the DIN5008 report layout. - Select Send by Post. - Enable Developer Mode and navigate to Settings → Technical → Email → Snailmail Letters. - Open the generated letter and send it. **Observed behavior:** The address blocks are incorrectly aligned when the DIN5008 report is rendered for snailmail. The information block and recipient address do not follow the expected vertical positioning. **Cause:** The DIN5008 layout previously applied vertical alignment rules to its table cells. These rules were removed while adapting the layout to the invoice table structure and its customizations, such as the position column and line numbering. While this alignment is no longer required for the regular DIN5008 invoice layout, the snailmail layout relies on it to correctly position the sender/invoice information and recipient address blocks. **Fix:** Add a `snailmail` class to the DIN5008 invoice section when `snailmail_layout` is present in the rendering context. Restore the required vertical alignment rules scoped to this class so they only affect snailmail reports, without changing the regular DIN5008 layout. **References** * **PR:** [#201225 – DIN5008 layout improvements](https://github.com/odoo/odoo/pull/201225) * **Ticket:** [6387869](https://www.odoo.com/odoo/project/49/tasks/6387869) opw-6387869 Forward-Port-Of: odoo/odoo#286056 Forward-Port-Of: odoo/odoo#285891
Refunds in Italian POS now take cashiers to the payment page for the refund order, rather than the original sale or product screen. This prevents checkout confusion and helps stores using Italian fiscal printers complete refund flows correctly.
Original PR description
**Issue**: 1. From versions 18.4 to 19.1 inclusive, the system redirects to the product screen; 2. From version 19.2 onward, the redirection targets the payment page of the original order instead of the refund order. **Expected behavior**: The system navigates to the payment page for the refund order. **Steps to reproduce**: - Set up an Italian fiscal printer; - Open a POS session and process an order; - Create a refund for the order. [Ticket link](https://www.odoo.com/odoo/project/49/tasks/6499079) opw-6499079 Forward-Port-Of: odoo/enterprise#130044 Forward-Port-Of: odoo/enterprise#129758
The Polish bank verification feature now avoids processing all existing payments during installation. This prevents installation failures or crashes for companies with large payment histories, making upgrades and module setup more reliable.
Original PR description
account.payment model computes every record l10n_pl_verification_id at module installation (l10n_pl_bank_verification), causing crash in case of db with a large number of records wrong method name correction: _auto_init instead of init and call super after creating the db column see odoo/odoo#282504 Forward-Port-Of: odoo/odoo#285968
Long delivery method names on the eCommerce checkout page now wrap instead of overflowing the page. This keeps the checkout layout readable and usable for customers when delivery options include long location or zone lists.
Original PR description
Issue ----------- Long delivery method names containing lists of locations/zones do not wrap properly on the eCommerce checkout page, causing the layout to overflow. Cause of the issue -----------…
Issue ----------- Long delivery method names containing lists of locations/zones do not wrap properly on the eCommerce checkout page, causing the layout to overflow. Cause of the issue ----------- The first column of `[.o_delivery_method_row](https://github.com/odoo/odoo/blob/saas-19.3/addons/website_sale/static/src/scss/website_sale_delivery.scss#L2)` uses `minmax(max-content, 1fr)`. `max-content` prevents the column from shrinking when the delivery method name is too long. Steps to reproduce ----------- 1. Create a Delivery Method with a long list of locations/zones in its name. 2. Go to the eCommerce checkout at the address page. 3. Observe that the delivery method name does not wrap and breaks the layout. Before Fix ----------- The `max-content` minimum prevents the delivery method name from wrapping, causing the layout to overflow. <img width="1781" height="852" alt="image" src="https://github.com/user-attachments/assets/1150a8ef-e2d8-49ab-9553-fe9728258060" /> After Fix ----------- Change `max-content` to `min-content` so the column can shrink and the delivery method name wraps. <img width="1882" height="890" alt="image" src="https://github.com/user-attachments/assets/84cfd5a4-796d-4b9f-bfdb-c18434f8b67f" /> [OPW- 6486780 ](https://www.odoo.com/odoo/project/70/tasks/6486780) [UPG- 4609267 ](https://upgrade.odoo.com/odoo/upgrade.request/4609267) Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284714
The expense app now uses the correct "approved" state name in its views. This avoids confusing or inconsistent wording for users reviewing expense records.
Original PR description
Use the correct state name (approved) @Tecnativa --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285950
This fix updates an Indonesian e-Faktur test so it explicitly applies the required tax instead of relying on automatic defaults. It helps prevent false build failures and keeps e-Faktur download checks reliable.
Original PR description
Issue: In some build, when creating the invoice line it did not assign the default tax so it raise an error when downloading efaktur Fix: Assign the tax line manually in the unit test instead of relying on default taxes issue-[946227](https://runbot.odoo.com/odoo/error/946227) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285902
Forum information links are now treated as regular links in the website editor instead of buttons. This prevents irrelevant button styling controls from appearing, making forum page editing clearer and less confusing.
Original PR description
Steps to reproduce: - Go to a forum page. - Open the website editor. - Select the "About this forum" link in the sidebar. => Button styling options are shown for a regular link. Before this commit, forum information links used button classes, which made the editor expose button styling options for them. After this commit, the `btn`, `btn-sm`, and `btn-link` classes are replaced with `small` so the editor treats these elements as regular links on desktop and mobile. task-6259086 Forward-Port-Of: odoo/odoo#283156
The website editor no longer shows a theme-based background option for tab sections because it did not work in this version. This avoids confusing website builders with a choice that would not apply correctly.
Original PR description
The theme background options (`o_cc` classes) on the `s_tabs` snippet's tabs doesn't work since 18.4 (html_builder refactor). It was not supported either in previous versions. We decided to fix it so it would be useable in master (20.0) but leave stable versions as is, by restraining the available tabs and removing the theme one. task-5951656 Forward-Port-Of: odoo/odoo#277528
The website editor's block search clear icon now changes the cursor to a pointer when users hover over it. This small visual cue makes it clearer that the icon can be clicked to clear the search text, improving usability in browsers that show the icon.
Original PR description
Steps to reproduce: - Open the website editor. - Open the "Insert a block" dialog. - Enter text in the search bar. - Hover over the clear icon. => The cursor does not indicate that the icon is clickable. Before this commit, the search clear icon kept the default cursor. After this commit, the clear icon uses a pointer cursor to indicate that it is clickable. Note that Firefox does not natively add this clear icon to search inputs, unlike Chrome. This fix only affects browsers that render it. task-6259086 Forward-Port-Of: odoo/odoo#283435
This fix prevents UPS deliveries from being rejected when an invoicing address has no name. The system now falls back to a valid partner name for shipment invoicing details, helping affected orders confirm successfully.
Original PR description
Issue ----- By default, invoicing addresses of existing partners are created without a name. This leads to the deliveries being rejected by UPS. Steps to reproduce ----- - Set Up UPS - Create a Customer - Create an invoicing address with no name - Create a SO for the partner & confirm - UPS delivery - Open the picking and confirm it > UPS rejects the shipment /!\ I could not reproduce in testing environment, so this is based off user steps in their production DB. /!\ Cause ----- The partner being used in `_set_invoice` was changed in #119747 but this use case was missed due to the error not occuring in test mode. ----- Ticket: opw-6485164 Forward-Port-Of: odoo/enterprise#128933
The Romanian tax return list now shows the specific declaration name "D300" instead of the generic label "Tax". This makes it easier for users to identify and select the correct Romanian tax declaration when preparing returns.
Original PR description
Before this commit: When generating a Romanian tax return, one of the return types in the list was labeled "Tax", which was too generic to know which specific tax declaration it referred to. After this commit: The tax return is now renamed to "D300", making it easy to identify this return in the list instead of seeing a generic "Tax" label. task - 6388087 Forward-Port-Of: odoo/enterprise#124583
The Helpdesk unread tickets filter now correctly treats tickets with the latest automatic system message as still unanswered. This helps support teams avoid missing website-submitted tickets that need attention.
Original PR description
**Steps to reproduce:** - Install website_helpdesk. - Create a team and enable website form. - Create a ticket through the website. - Apply the Unread filter. **Issue:** system generated message, such as message authored by OdooBot, were not considered when determining whether a ticket was unanswered. **Cause:** the search method only considered the last message when its author matched the ticket's partner. **Fix:** Consider a ticket unanswered when the last message's author matches the ticket's partner, or when the last message is an automatic system generated message. task-5138678 Forward-Port-Of: odoo/enterprise#130100
Purchase orders for products billed on ordered quantities now generate accrued expense entries as soon as the order is confirmed, even before receipt or invoicing. This prevents missing or incorrect accruals and improves accounting accuracy for affected purchase workflows.
Original PR description
Version: -------- - 19.0+ Steps to reproduce: ------------------- - Install `stock`, `purchase`, and `accountant` - Create a storable product with: - Tracking Inventory enabled - Control Policy set…
Version: -------- - 19.0+ Steps to reproduce: ------------------- - Install `stock`, `purchase`, and `accountant` - Create a storable product with: - Tracking Inventory enabled - Control Policy set to **Ordered Quantities** - Create and confirm a Purchase Order with some unit price - Do not receive or invoice the order - From the Purchase Order gear menu, click **Accrued Expense Entry** Issue: ------ The Accrued Expense Entry wizard opens, but no accounting lines are generated. For products invoiced on **Ordered Quantities**, the ordered quantity should already be accrued even though nothing has been received. Cause: ------ This issue was introduced after this changes [commit](https://github.com/odoo-dev/odoo/commit/81f25bc57b8433a65bf33950c64dc7582240a229) Previously, the accrual wizard relied on the stored `qty_to_invoice` field, whose computation already respected the product's Control Policy. For products invoiced on **Ordered Quantities**, `_compute_qty_invoiced()` computes the quantity to invoice from the ordered quantity: https://github.com/odoo/odoo/blob/810a02a577c2811dc5c12f0abf45eebb9cf96d00/addons/purchase/models/purchase_order_line.py#L147-L152 The refactoring replaced this logic with the new `amount_to_invoice_at_date` field, which always computes the invoicable quantity as: `qty_received_at_date - qty_invoiced_at_date` https://github.com/odoo/odoo/blob/65dbcabcd243abf24d6d3c3788d2caff66485790/addons/purchase/models/purchase_order_line.py#L282-L285 This formula ignores the product's Control Policy. For products invoiced on Ordered Quantities, before any receipt: `qty_received_at_date` = 0 `qty_invoiced_at_date` = 0 therefore: `amount_to_invoice_at_date` = 0 The Accrued Expense wizard filters out lines whose `amount_to_invoice_at_date` is zero: https://github.com/odoo/odoo/blob/65dbcabcd243abf24d6d3c3788d2caff66485790/addons/account/wizard/accrued_orders.py#L168-L178 As a result, the purchase order line is excluded entirely and the wizard produces no accounting entries. The same assumption is also used later in `account.accrued.orders.wizard._compute_move_vals()` when computing tax-included amounts, causing incorrect accrual values for Ordered Quantities products whenever receipts and invoices differ. Fix: ---- Introduce `_get_qty_to_invoice_at_date()`, mirroring the existing purchase_method logic used by _compute_qty_invoiced(). The helper returns: product_qty - qty_invoiced_at_date for Ordered Quantities products; `qty_received_at_date` - `qty_invoiced_at_date` for Received Quantities products. Now products invoiced on `Ordered Quantities` become accruable as soon as the Purchase Order is confirmed; --- opw-6290782 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284507 Forward-Port-Of: odoo/odoo#276435
The editor no longer shows an inactive wand icon when users open the link popover for an image with a link. This avoids confusion by removing a control that did not work in that context.
Original PR description
**Current behavior before PR:** Steps to reproduce the issue: - Add an image - Add a link to the image - Put cursor just right after the image link so that link popover is opened - Notice that there is a wand icon in link popover to replace title, clicking on it does nothing **Desired behavior after PR:** There should be no replace title icon in popover for image-link. task-6420902 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286119 Forward-Port-Of: odoo/odoo#279076
This fixes an issue where pages using Odoo live chat could accidentally block browser keyboard shortcuts such as Alt+D. Shortcuts are now only intercepted when Odoo actually has shortcut hints to show, preserving normal browser behavior on embedded live chat pages.
Original PR description
Description of the issue/feature this PR addresses: When `im_livechat` (or any page) boots the OWL web stack with no `[data-hotkey]` / `withOverlay` targets, pressing Alt still called…
Description of the issue/feature this PR addresses: When `im_livechat` (or any page) boots the OWL web stack with no `[data-hotkey]` / `withOverlay` targets, pressing Alt still called `preventDefault()` in `hotkey_service`. That blocked browser shortcuts such as Alt+D (focus address bar) on websites that embed the livechat scripts. See https://github.com/odoo/odoo/issues/267928 Current behavior before PR: - Pressing the overlay modifier (Alt, or Ctrl on macOS mapped to `"alt"`) always set `overlaysVisible = true` and called `preventDefault()`, even when there were no hotkeys to overlay. - A follow-up key (e.g. D while Alt is held) then also hit `preventDefault()` because overlays were considered visible. - Loading `/im_livechat/loader/...` + `assets_embed.js` on an external site therefore broke browser Alt shortcuts. Desired behavior after PR is merged: - `addHotkeyOverlays` returns whether overlays were actually displayed. - `preventDefault` on the overlay modifier runs only when there is at least one overlay target. - Pages with no hotkeys (typical livechat embed) leave browser shortcuts alone. - When hotkeys exist, Alt still shows overlays and cancels the default, same as before. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284145
The Helpdesk team card layout has been adjusted so the email alias lines up neatly with the team name. This fixes a small visual inconsistency, making the team overview easier to read and more polished.
Original PR description
In this commit, we remove the margin before the mail alias, ensuring aligment within the helpdesk team card. task-6416578 Forward-Port-Of: odoo/enterprise#129865
GSTR-2B returns now show the correct action to fetch data instead of an unrelated submit option. This restores the expected workflow so users can retrieve and reconcile their GSTR-2B information without confusion.
Original PR description
Stop showing the 'Submit' button on GSTR-2B returns and show the 'Fetch GSTR-2B' button again so users can fetch and reconcile their GSTR-2B data. After the recent tax returns refactor (603443c), GSTR-2B returns started showing a 'Submit' button that is not part of their flow, while the 'Fetch GSTR-2B' button was no longer displayed. task-6529017
The GSTR-2B return screen now keeps the correct Validate action visible after checks pass, instead of showing an irrelevant Submit button. This prevents confusion because GSTR-2B returns are validated and then fetched for reconciliation, not submitted through this flow.
Original PR description
On GSTR-2B returns, once all the checks pass, keep showing the 'Validate' button instead of the 'Submit' button. After the return is validated 'Fetch GSTR-2B' button appears so the data can be fetched and reconciled. In the generic returns flow, after the refactor (603443c) the 'Validate' button disappears and a 'Submit' button is shown once checks pass. GSTR-2B returns are not submitted — they are validated and then fetched — so the 'Submit' button is not relevant for them. task-6529017
Basic receipts in Peruvian Point of Sale now hide extra electronic invoice information such as the amount in words. This keeps simplified receipts concise while preserving the additional details on full receipts where they belong.
Original PR description
Step to reproduce - install l10n_pe_edi_pos with demo and switch to PE company - from settings> "Signature Provider" set it to SUNAT - create a pos, enable "Basic Receipt" from settings - open pos…
Step to reproduce - install l10n_pe_edi_pos with demo and switch to PE company - from settings> "Signature Provider" set it to SUNAT - create a pos, enable "Basic Receipt" from settings - open pos and fulfill a order - from feedback screen, print > print basic recipt Observation: - `Amount In Word` is visible in basic receipt, we should not show such info in basic receipt Cause: - commit [1] introduces the template `l10n_pe_edi_pos.pos_order_receipt`, which adds the info block to the receipt using xpath `<xpath expr="//div[contains(@t-if, 'use_self_invoicing')]" position="before">` - this inserts the block before the [target div](https://github.com/odoo/odoo/blob/1ace23afe8a937fc1dc53879f33ca591fd5d25b8/addons/point_of_sale/receipt/pos_order_receipt.xml#L70-L86), which is independent of the `basic_receipt` flag, causing the block to always be visible [1] https://github.com/odoo/enterprise/commit/a0c4f841cde0fcfda0a0c57f865f0eff6b6d6afe Fix: - place the block so it is shown only when `basic_receipt` is false - update the xpath expression to `prices` div ( here `basic_receipt` is false `//div[@name='prices']` with `position="inside"` After fix (for full receipt) <img width="257" height="349" alt="image" src="https://github.com/user-attachments/assets/3932cae1-3ceb-42ad-9ce4-16a9bd4fea7d" /> opw-6383358 Forward-Port-Of: odoo/enterprise#125118
The mail app now avoids showing repeated error dialogs if the browser clears or blocks the storage used for unread message counts. This keeps the user interface stable while preserving the app badge as a best-effort convenience feature.
Original PR description
Description of the issue/feature this PR addresses: The unread counter feeding the PWA app badge is written to the `odoo-mail-unread-db` IndexedDB database, through a connection opened once, at…
Description of the issue/feature this PR addresses: The unread counter feeding the PWA app badge is written to the `odoo-mail-unread-db` IndexedDB database, through a connection opened once, at module load, and cached for the life of the page by the bundled idb-keyval (3.2.0), which cannot reopen it. When the browser drops the origin's storage (eviction under disk pressure, site data cleared, a privacy extension purging it), that connection is closed for good, and as `updateAppBadge()` discards the promise returned by `idbKeyval.set()`, the rejection reaches the user as a client error dialog. Reported in production on a backend tab left open overnight (Firefox, 19.0): ``` UncaughtPromiseError > InvalidStateError Uncaught Promise > IDBDatabase.transaction: Can't start a transaction on a closed database ``` Reproduced on a demo database below, with `?debug=assets` so that the stack points at the source: lines 23 and 24 of the vendored idb-keyval are the `db.transaction()` call of `_withIDBStore`, on the connection cached at module load. <img width="1600" height="590" alt="error-dialog-debug" src="https://github.com/user-attachments/assets/e2b1aa46-501a-43d4-b4c0-20def1f529ef" /> Current behavior before PR: 1. log into the backend and leave the tab open 2. in the devtools, Application > Storage, tick *only* "IndexedDB" and click "Clear site data", as the browser itself does when it evicts the origin (the session cookie is left untouched, so the tab keeps working) 3. receive a message, or do anything else that changes the unread counter The dialog opens, and opens again on every counter update for the whole life of the tab, since the dead connection is never replaced; the counter is not saved any more either. Two variants of the same code: the write also rejects, without anything being cleared, when the origin runs out of storage quota (`QuotaExceededError`), and when the browser forbids storage for the origin, `indexedDB.open()` throws during module evaluation, so `store_service_patch.js` fails to load entirely. Desired behavior after PR is merged: The store is opened lazily, dropped whenever saving the counter fails, and the write is retried once on a new connection: a single counter update after the connection was closed saves it again. Opening the database is guarded too, for the synchronous throw. When the retry fails as well the error is ignored, the app badge being cosmetic. `mail/static/tests/web/app_badge.test.js` covers the retry, the recovery of a permanently closed connection, and the database that cannot be opened at all. The three tests fail on the current code with the uncaught `IDBDatabase.transaction` error. Introduced in 19.0 by c04c4cb715902fe95618a15e18233cd001bdb304, and identical from saas-19.1 to master, hence this PR against 19.0. The corporate CLA for ERPVibe Limited is submitted in #283477. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283480