Thursday, September 3, 2026
20 changes · master
Resolved issues and error corrections
This fix prevents the payroll dashboard from crashing when a company has payroll warnings across multiple pay schedules, such as monthly and weekly schedules. It ensures cached dashboard items stay distinct, so users can reliably return to payroll after refreshing the browser.
Original PR description
**Steps to reproduce** - Go to Hong Kong company - Go to payroll - Go back and refresh your browser - Go to payroll **Crash:** OwlError: Got duplicate key in t-foreach: pending_175_2026-08-31 Error:…
**Steps to reproduce**
- Go to Hong Kong company
- Go to payroll
- Go back and refresh your browser
- Go to payroll
**Crash:**
OwlError: Got duplicate key in t-foreach: pending_175_2026-08-31
Error: Got duplicate key in t-foreach: pending_175_2026-08-31
at PayrollDashboardComponent.template_hr_payroll_Dashboard (eval at compile (https://123484110-master-all.runbot135.odoo.com/web/assets/debug/web.assets_web.js:16100:14), <anonymous>:59:49) (/web/static/lib/owl/owl.js:7070)
at RootFiber.render (https://123484110-master-all.runbot135.odoo.com/web/assets/debug/web.assets_web.js:12537:28) (/web/static/lib/owl/owl.js:3507)
at ComponentNode.render (https://123484110-master-all.runbot135.odoo.com/web/assets/debug/web.assets_web.js:12795:15) (/web/static/lib/owl/owl.js:3765)
**Reason:**
04065101644 introduced caching on payroll dashboard. Cached pending warnings were keyed by id + date only, dropping the schedule that distinguishes cards for the same warning across pay schedules (e.g. monthly vs weekly).
Colliding keys crashed the dashboard with a duplicate t-foreach key, notably on l10n_hk which mixes both schedules.
task-6522399Attendance managers can now open and manage attendance records without being blocked by overtime rule access errors. The change keeps sensitive HR rule details read-only for non-HR users while allowing attendance workflows to continue smoothly.
Original PR description
Issue ===== The overtime rules searches the model `hr.version` for versions' data. However, an attendance manager does not have access to `hr.version`, hence an access error is raised. Fix ===== - Use `sudo()` on read and search operations on `hr.version`. - Use a dispatcher server action to trigger the ruleset action with the appropriate context to make ruleset data `readonly` for non-HR users. Also see related [PR](https://github.com/odoo/odoo/pull/275676) TaskID-6128198
This update corrects mismatched internal references in the HTML editor so existing features keep working as expected. It restores behaviors such as signature handling, image updates after undo or redo, and table cell selection updates, reducing small editing glitches for users.
Original PR description
Description of the issue this PR addresses: Several plugin declarations had drifted from the code they describe. This PR fixes such issues, see the individual commit messages for details. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Belgian payroll rules were updated so the 3000 deduction is calculated correctly for the second and third quarters of 2026. This helps employers produce accurate payroll and social security reporting for the affected periods.
Original PR description
Forward-Port-Of: odoo/enterprise#126091 Forward-Port-Of: odoo/enterprise#124034
This fix ensures Sign documents display at the correct size when users switch between multiple documents. It also prevents editing popovers from remaining visible after leaving the template editor, reducing confusion when navigating to another screen.
Original PR description
When there are several documents to be viewed, all viewers are loaded at the same time, but only the current one is visible. Because the other viewers are hidden, their automatic zoom is calculated incorrectly and is never recalculated. As a result, when switching documents, the page has the wrong size. In the template editor, the popover for a sign item belongs to the popover service, not to the document. Because of this, when leaving the page, for example using the breadcrumb, the popover stays open and appears on the next view. task-6530400
This fixes a problem that could cause Knowledge pages with foldable sections to crash after a recent technical update. Users can now open and view these embedded sections reliably again.
Original PR description
In this [owl3 adaptation], `ReadonlyFoldableSection` `static props` were replaced using `useProps`, but the `FoldableSection` child class was still using the `static props` form, rendered ineffective. This meant that OWL was not passing the `host` props to `FoldableSection` embedded components, resulting in a crash. [owl3 adaptation]: https://github.com/odoo/enterprise/commit/a8def7a3de4949474741d5c9935c39f3d6cb84cf task-6533835
Unbuild orders for serial- or lot-tracked manufactured products now honor the specific lot or serial number selected by the user. This prevents the system from accidentally unbuilding the oldest available item instead, improving inventory accuracy and trust in manufacturing operations.
Original PR description
Steps to Reproduce: - Create a Serial Number tracked product. - Create a Manufacturing Order (MO) for quantity 5. - Create and assign serial numbers: SN1, SN2, SN3, SN4, SN5. - Mark the MO as Done. - Create an Unbuild Order for quantity 1. - Select SN4 in the lot/serial field. - Mark the Unbuild Order as Done. - Check Product Moves, SN1 gets unbuilt Issue: When creating an Unbuild Order for a tracked product and explicitly selecting a specific serial/lot number to unbuild, the system ignores the user's choice. Instead, it falls back to the default FIFO strategy and automatically unbuilds the oldest available serial/lot number from the source location. Task-6326772 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283651 Forward-Port-Of: odoo/odoo#272525
Manufacturing orders for serial-tracked products using make-to-order purchased components no longer show an incorrect consumption warning when quantities are actually correct. This prevents unnecessary user confusion and allows the production flow to 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#281258Italian POS refunds now take users to the payment page for the new refund order, not the original order or product screen. This prevents cashier confusion and helps complete refund transactions correctly when using an Italian fiscal printer.
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
This fix prevents the Polish bank verification module from recalculating all existing payments during installation. It helps large databases install or update the module reliably without running into crashes caused by too much processing at once.
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
UPS shipments could be rejected when a customer's invoicing address did not have its own name. The delivery integration now falls back to a suitable partner name, helping affected shipments proceed without requiring manual address cleanup.
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
Payroll search filters have been updated after a recent change to how payslip-related names are stored. This restores reliable searching for payroll lines and worked days, while removing a payslip-name filter that no longer worked correctly.
Original PR description
We recently did a refactor of how names are handled for payslips, lines, and worked days (See #128134). They are now non-stored fields, and some filters still use those fields, effectively breaking the search. For the payslip name, we decided not to replace the filter with a complex domain and simply delete it. For the line / worked days name, we now use a domain on the salary rule / work entry type and the custom name, the same way it is computed. Task-6511349
The Helpdesk unread ticket filter now correctly treats tickets as unread when the latest update is an automatic system message, such as one from OdooBot. This helps support teams avoid missing customer tickets created through the website that still 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
This fix prevents invalid e-invoicing response records from being created when the French PDP service does not return a tracking identifier. It avoids scheduled status update failures, helping invoice and vendor bill e-invoicing processing continue reliably.
Original PR description
Steps to reproduce: - Install `l10n_fr_pdp` and `l10n_be` module - Activate `French e-invoicing` (you need to put your DB in test mode) (i.e: `account_peppol.edi.mode = 'test'` in system parameter)…
Steps to reproduce:
- Install `l10n_fr_pdp` and `l10n_be` module
- Activate `French e-invoicing` (you need to put your DB in test mode)
(i.e: `account_peppol.edi.mode = 'test'` in system parameter) Refer this Documentation https://www.odoo.com/documentation/19.0/applications/finance/fiscal_localizations/france.html?highlight=e%20invoicing#localizations-france-e-invoicing-fac-elec-config
- Create a Invoice and Sent with `E-invoicing`
- Run `PEPPOL: retrieve new documents` Cron
- In Invoice Other Info > `E-Invoicing Status` should be in `Done` state
- Now Vendor Bill is created for that invoice > Cancel that bill with reason > Check `E-Invoicing Status` response for bill(one response will be without UUID)
- Go to schedule actions > `PEPPOL: update message status`
- Run it and get the traceback: `KeyError: 'false'`
Issue:
When sending a lifecycle response to the French PDP, `_pdp_send_response` calls the `/api/pdp/1/send_response` endpoint and expects IAP to return a `message_uuid` for each response.
However, IAP return a response without a message UUID, for example: ` {'messages': [{'message_uuid': False}]}` `_pdp_send_response` currently assumes that every returned message has a valid UUID and creates an `account.peppol.response` with:
```
'peppol_message_uuid': False
'peppol_state': 'processing'
```
This leaves an `account.peppol.response` in `processing` state without a UUID that can be used to track it.
During the next execution of `_cron_peppol_get_message_status`, `_peppol_get_message_status` retrieves this response through `_peppol_get_documents_for_status` and builds `uuid_to_record` using `peppol_message_uuid` as the key. The resulting mapping contains the Python value `False` as a key.
The cron then calls the PDP `1/get_document` endpoint with this invalid UUID. IAP returns it as the string `'false'`, which is passed to `_peppol_process_messages_status`. The French PDP implementation tries to retrieve the corresponding record with: `uuid_to_record[uid]`
Since the mapping contains `False` while `uid` is `'false'`, this raises: `KeyError: 'false'`
This failure prevents the status cron from completing the processing of the messages.
Solution:
Avoid creating the `account.peppol.response` when IAP does not return a `message_uuid`. A response without a UUID cannot be tracked through the PDP status flow, so creating it in `processing` state only leaves an
invalid record that will later cause the status processing to fail.
opw-6453133
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#286147
Forward-Port-Of: odoo/odoo#281691This fixes a problem that could stop the scheduled retrieval of Turkish Nilvera e-Dispatch purchase PDFs. Businesses using this localization can now retrieve these documents reliably without the process failing due to an attachment lookup error.
Original PR description
## Steps to Reproduce: - Install `l10n_tr_nilvera_edispatch` module. - Run "**Nilvera: retrieve e-Dispatch purchase PDFs**" Scheduled Action. ## Error: ``` ValueError: Binary field stored in…
## Steps to Reproduce:
- Install `l10n_tr_nilvera_edispatch` module.
- Run "**Nilvera: retrieve e-Dispatch purchase PDFs**" Scheduled Action.
## Error:
```
ValueError: Binary field stored in attachment, accepts only existence check; skipping domain in condition ('l10n_tr_nilvera_edispatch_xml_file', 'in', OrderedSet([True]))
```
## Cause:
After commit https://github.com/odoo/odoo/commit/3641f23a9b4cd401444ca3371873d8123922f7b1, The condition operators `=` and `!=` are normalized to `in` and `not in` respectively.
As a result:
```
('field', '=', True) becomes ('field', 'in', OrderedSet([True])) and
('field', '=', False) becomes ('field', 'in', OrderedSet([False]))
```
After this normalization, the domain optimizer `_optimize_type_binary_attachment()` is applied - [1].
For attachment-type binary fields, it only allows `in/not in` operators, and a value should be `{False}`.
Therefore, the condition (converted) `('l10n_tr_nilvera_edispatch_xml_file', 'in', [True])` is rejected.
Binary fields with `attachment=True` are not stored as a boolean value. When converting their domain to SQL, `condition_to_sql()` - [2] handles them as an EXISTS check on `ir.attachment` to determine whether an attachment exists.
## Fix:
This commit replaces the `= True` in the condition with `!= False`.
[1] - https://github.com/odoo/odoo/blob/762fd7c0b65e8f8e3eb59eb8a57b1394cb176339/odoo/orm/domains.py#L1782-L1784
[2] - https://github.com/odoo/odoo/blob/762fd7c0b65e8f8e3eb59eb8a57b1394cb176339/odoo/orm/fields_binary.py#L217-L218
sentry-7627832395
Forward-Port-Of: odoo/odoo#284401Belgian payroll now treats removal of a company car from a contract like a car change when prior payslips may already have been declared. This prevents an error and ensures users get the needed confirmation prompt for changes that can affect ATN and CO2 payroll contributions.
Original PR description
Deselecting a car on a contract version raises a singleton error because `version_requires_prompt` is called on an empty `fleet.vehicle` recordset. Removing a company car alters Belgian ATN/CO2 contributions. If past payslips were already declared in a DMFA, removing the car carries the same compliance impact as swapping cars and must trigger the confirmation prompt. task-6524324
Fixed an issue where accrued expense entries were not created for purchase orders using products invoiced based on ordered quantities. This ensures finance teams can recognize expected purchase expenses as soon as the order is confirmed, even before goods are received or invoiced.
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
This fix stops repeated fast clicks from creating duplicate timesheet entries or showing the same new timesheet multiple times in the interface. It improves reliability for users working on slow connections by ensuring each save or suggestion action is handled only once at a time.
Original PR description
Steps to reproduce: 1. Open the ActivityWatch timesheets view. 2. Throttle the network speed to simulate a slow connection. 3. Rapidly click "Add" on an ActivityWatch suggestion. 4. Click 'New', fill in the details, and rapidly click "Create" (or mash Ctrl+Enter). Issue: - Suggestion List: Multiple duplicate timesheets are created in the database. - Creation Form: The newly created timesheet appears multiple times in the UI list on the left side, even though only one might be created in the database. Cause: Both the `onTake` (ActivityWatch list) and `onSave` (Timesheet form) methods are asynchronous. Without a concurrency lock, rapid user interactions trigger these methods multiple times before the initial network request finishes, causing parallel ORM calls and duplicate UI array pushes. task-6462515 Forward-Port-Of: odoo/enterprise#130101 Forward-Port-Of: odoo/enterprise#127806
Fixed an issue that could stop Odoo's point-of-sale interface from loading when accessed over a local network IP address instead of a secure or localhost connection. This helps businesses run POS setups more reliably in common in-store network configurations.
Original PR description
Steps to reproduce: 1. Start Odoo with `--http-interface=0.0.0.0` 2. Access the POS interface via IP address (e.g., http://192.168.1.100:8069) 3. The JavaScript bundle fails to load with: "Cannot read properties of undefined (reading 'writeText')" Cause: The `navigator.clipboard` API is only available in secure contexts (HTTPS or localhost). When accessing via IP address over HTTP, the browser denies clipboard access for security reasons, making `navigator.clipboard` undefined. The code directly accessed `navigator.clipboard.writeText` at module load time without checking if the clipboard object exists. Fix: - Use optional chaining when capturing the original writeText reference - Add guard checks in both allowClipboardWrite and restoreClipboardWrite before accessing navigator.clipboard This allows the module to load successfully.
Odoo now avoids showing repeated error dialogs when the browser removes or blocks the storage used for the mail unread badge. The unread badge update is retried safely and ignored if storage remains unavailable, keeping the main interface usable.
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