Wednesday, August 5, 2026
39 changes · saas-19.1
Enhancements to existing features
This update backports expanded test coverage and supporting tools for Marketing Automation, including checks for message failures, bounces, campaign enrollment, and scheduled synchronization behavior. It helps reduce the risk of regressions in automated campaigns, especially when participant synchronization or message delivery encounters errors.
Original PR description
Backport various tests added in Odoo 19.4+ in order to better spot potential regressions. Add new tests for synchronization cron behavior, notably in case of failure. Forward-Port-Of: odoo/enterprise#126334
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites in addons tests reach waitForSteps and not one of them passes an explicit timeout, so 2 seconds is what every step wait gets. The problem is that the RPC chain a step wait sits on takes longer than that on a loaded machine. Measured from openDiscuss resolving to the message being in the DOM: -
Original PR description
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites…
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites in addons tests reach waitForSteps and not one of them passes an explicit timeout, so 2 seconds is what every step wait gets. The problem is that the RPC chain a step wait sits on takes longer than that on a loaded machine. Measured from openDiscuss resolving to the message being in the DOM: - 250 to 460ms on an idle machine; - 867 to 5258ms over 10 runs with the CPU throttled 4x, which is what a busy runbot looks like, 3 of the 10 over 2 seconds; - 1474 to 6912ms with the CPU throttled 6x, 5 of 6 over 3 seconds. Note that a longer timeout costs nothing on a green build: the timer is cleared as soon as the steps are in, so it only delays the report of a test that was going to fail anyway. This commit raises both to 10 seconds, the delay a tour step already gets in macro.js. test_js.py runs the presets with timeout=15000, so hoot fails the test itself at 15 seconds and 10 leaves room for the rest of the test. Companion of https://github.com/odoo/odoo/pull/279983 to fix https://runbot.odoo.com/odoo/error/944188 kind of issues. Forward-Port-Of: odoo/odoo#279984
The feature was never merged on IAP/Internal's side and we now have a new task to move the setting up of the auto-refill from the local db to the IAP server, so the feature is no longer relevant on the client side. Task-6397951
Original PR description
The feature was never merged on IAP/Internal's side and we now have a new task to move the setting up of the auto-refill from the local db to the IAP server, so the feature is no longer relevant on the client side. Task-6397951
Backport various tests added in Odoo 19.4+ in order to better spot potential regressions. Forward-Port-Of: odoo/odoo#279677
Original PR description
Backport various tests added in Odoo 19.4+ in order to better spot potential regressions. Forward-Port-Of: odoo/odoo#279677
Before this commit, contains() and its variants gave the client 3 seconds, and the bus helpers 2 seconds. The problem is that the first wait after openDiscuss pays for the whole mount, /mail/data and /discuss/channel/messages. Measured from openDiscuss resolving to the message being in the DOM: - 250 to 460ms on an idle machine; - 867 to 5258ms over 10 runs with the CPU throttled 4x, which is what a busy runbot looks like, 3 of the 10 over 2 seconds; - 1474 to 6912ms with the CPU throttl
Original PR description
Before this commit, contains() and its variants gave the client 3 seconds, and the bus helpers 2 seconds. The problem is that the first wait after openDiscuss pays for the whole mount, /mail/data and…
Before this commit, contains() and its variants gave the client 3 seconds, and the bus helpers 2 seconds. The problem is that the first wait after openDiscuss pays for the whole mount, /mail/data and /discuss/channel/messages. Measured from openDiscuss resolving to the message being in the DOM:
- 250 to 460ms on an idle machine;
- 867 to 5258ms over 10 runs with the CPU throttled 4x, which is what a
busy runbot looks like, 3 of the 10 over 2 seconds;
- 1474 to 6912ms with the CPU throttled 6x, 5 of 6 over 3 seconds.
"Reactions are ordered by id" fails 1 run in 60 at 4x for that reason.
Note that a longer timeout costs nothing on a green build: the timer is cleared as soon as the element is there, so it only delays the report of a test that was going to fail anyway.
This commit raises both to 10 seconds, the delay a tour step already gets in macro.js. test_js.py runs the presets with timeout=15000, so hoot fails the test itself at 15 seconds and 10 leaves room for the rest of the test.
This should also close most of the open runbot errors shaped like:
Failed to find x of "..." (Timeout of 3 seconds). Found 0 instead.
The element does show up in those, just after the wait gave up.
https://runbot.odoo.com/odoo/error/944188
web companion https://github.com/odoo/odoo/pull/279984
Forward-Port-Of: odoo/odoo#280400
Forward-Port-Of: odoo/odoo#279983Comply with new provincial fiscal transparency regulations (CABA, Entre Ríos, Chubut, and other provinces still not defined) that mandate detailing Perception IIBB taxes on B2C invoices (Factura/Invoice B): - Some jurisdictions mandate a new description for IIBB perception taxes on the invoice, - We need to put the IIBB perception taxes in the special "Fiscal Transparency Regime" table, and exclude them from the standard tax table, task-6367087 Forward-Port-Of: odoo/odoo#278729 Forwar
Original PR description
Comply with new provincial fiscal transparency regulations (CABA, Entre Ríos, Chubut, and other provinces still not defined) that mandate detailing Perception IIBB taxes on B2C invoices (Factura/Invoice B): - Some jurisdictions mandate a new description for IIBB perception taxes on the invoice, - We need to put the IIBB perception taxes in the special "Fiscal Transparency Regime" table, and exclude them from the standard tax table, task-6367087 Forward-Port-Of: odoo/odoo#278729 Forward-Port-Of: odoo/odoo#277673
Resolved issues and error corrections
Date and datetime fields now disappear from the pivot setup popup once all available time options have already been used. This prevents users from adding duplicates, avoiding confusing drag-and-drop behavior and keeping spreadsheet pivot configuration consistent.
Original PR description
Current behavior before PR: - Date and datetime fields remained visible even when all their granularities were already added to the pivot. - Users could add the same field with the same granularity multiple times, creating duplicate IDs and causing unexpected drag and drop behavior. Desired behavior after PR is merged: - Hide date and datetime fields from the popup once all available granularities have already been added to the pivot. - This prevents duplicate field IDs and keeps the popup behavior consistent with spreadsheet pivots during drag-and-drop. Task: [6295794](https://www.odoo.com/odoo/project/2328/tasks/6295794) Forward-Port-Of: odoo/enterprise#123280
The self-ordering test flow now matches the current behavior where takeaway is selected automatically when it is the only option. This keeps validation reliable without changing the customer-facing ordering experience.
Original PR description
In this commit: - The takeaway preset is now automatically selected when it is the only available option. Remove the explicit "Takeaway" selection step from the tour to match the updated behavior. Task:6217791 Community PR : https://github.com/odoo/odoo/pull/274301 Forward-Port-Of: odoo/enterprise#122979
AI chat now stays usable when users navigate to areas such as Shopfloor where view switcher information is not available. This prevents an error when sending a message, reducing interruption for users who keep the AI chat open while moving between apps.
Original PR description
### Issue When AI chat is used in views where `config.viewSwitcherEntries` is not initialized, sending a message raises a `TypeError` because the code attempts to call `.map()` on an undefined value.…
### Issue
When AI chat is used in views where `config.viewSwitcherEntries` is not initialized, sending a message raises a `TypeError` because the code attempts to call `.map()` on an undefined value.
### Steps to Reproduce
[Video](https://drive.google.com/file/d/1i7kWDnmv4mebGtf1to12BNHCG5omBTXl/view?usp=sharing)
1. Click the **Ask AI** button.
2. Open the AI chat.
3. Keep it open and navigate to the **Shopfloor** app.
4. Send a message in the AI chat.
### Error
```text
TypeError: Cannot read properties of undefined (reading 'map')
at WithSearch.getCurrentViewInfo
```
### Fix
Safely handle cases where `config.viewSwitcherEntries` is undefined by using optional chaining and falling back to an empty array.
**Before**
```js
result.available_view_types = config.viewSwitcherEntries.map((v) => v.type);
```
**After**
```js
result.available_view_types =
config.viewSwitcherEntries?.map((v) => v.type) || [];
```
opw-6414684
Forward-Port-Of: odoo/enterprise#125821Users can now duplicate several maintenance requests at the same time without the system showing an error. This makes bulk maintenance work smoother and avoids interruptions when managing manufacturing-related maintenance requests.
Original PR description
Currently, when a user attempts to duplicate multiple maintenance requests simultaneously, the system throws a ValueError (Expected singleton). This PR fixes that. ### How to reproduce the issue: - Install `mrp_maintenance` module; - Open maintenance request list view; - Select multiple records and try to duplicate them using the Action button; - It will throw a traceback stating a singleton error. ### Expected behavior after PR is merged: Now multiple maintenance requests will be copied without raising any errors. Forward-Port-Of: odoo/enterprise#124255
This fixes a test issue where cash basis report checks depended on a specific generated account code. The tests now use the configured outstanding receipts account, preventing false failures when account codes vary between databases.
Original PR description
Description of the issue this commit addresses: Commit 63f5646cfd75 made the tests use the default outstanding account but hard-coded code 101403. In an all-module database, generated account codes depend on existing accounts, so Outstanding Receipts may use code 101404 and make otherwise correct report assertions fail. --- Desired behavior after this commit is merged: This commit derives the expected report line name from the configured outstanding receipts account, making the assertions independent of its generated code. --- runbot-[231581](https://runbot.odoo.com/odoo/error/231581) Forward-Port-Of: odoo/enterprise#125652
Updated incorrect Italian wording in the Balance Sheet reports so users see the proper field names when using the Italian language. This improves clarity and reduces confusion for accounting teams reviewing Italian financial statements.
Original PR description
### Steps to reproduce the issue: 1. Download Accounting and l10n_it 2. Install and switch to italian language 3. Go to Balance Sheets and select Balance Sheet (IT) 4. Some words are not correct [Here]( https://docs.google.com/spreadsheets/d/1-w83oAHTxDRIi-W_VSJiscNclw-yijzQUHOgMnTq7jE/edit?gid=0#gid=0) the wrong fields with their correct translations. opw-6424609 Forward-Port-Of: odoo/enterprise#126253
The Helpdesk Knowledge website feature now declares the dependency it needs to install correctly in special installation scenarios. This prevents setup failures when auto-installation is skipped, improving reliability for deployments and upgrades.
Original PR description
Trying to install website_helpdesk_knowledge with the flag --skip-auto-install would fail due to website_helpdesk_knowledge/views/helpdesk_views.xml referencing `is_published` which is only defined in `website` https://github.com/odoo/odoo/blob/4d60d5693f3d0253a28dd38412125b2fc6d6b41f/addons/website/models/mixins.py#L184 Reproduciton steps: odoo/odoo-bin --addons-path odoo/addons,odoo/odoo/addons,enterprise,design-themes -d oes_runbot --stop-after-init --log-level=test --max-cron-threads=0 -i website_helpdesk_knowledge --skip-auto-install Adding `website_knowledge` pulls in the relevant dependencies resulting in the field being found and valid Affects **18.0** and **19.0**, **nothing in between** Forward-Port-Of: odoo/enterprise#126260
Fixes an issue in the Barcode app where selecting items from a delivery containing both packaged and unpackaged products could leave two lines selected at once. This helps warehouse users avoid confusion and reduces the risk of processing the wrong delivery line.
Original PR description
**Steps to reproduce:** - Enable "Move Entire Packages" setting on deliveries - Make a product A, that has a package P1, on hand qty of 1 - Make product B that don't have a package, but on hand qty…
**Steps to reproduce:** - Enable "Move Entire Packages" setting on deliveries - Make a product A, that has a package P1, on hand qty of 1 - Make product B that don't have a package, but on hand qty of 1 - Make a delivery that has both of those products, requested qty of 1 for both - Mark it as todo - Go to the barcode app, select the delivery - Select the line with product B - Select the line with product A --> The line with product B is not unselected **Why the fix:** When we have a mix of packaged products and products without a package on the same operation, they are handled separately. The products without a package are handled in https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L388-L392 that calls https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L1277-L1284 But as you can see, there are no mention of the selected package line, which is stored in **this.lastScanned.packageId**. As we do not touch this variable, the selected package line stays selected. The same is true for the other way around, when we select a package line we call https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L394-L398 This function does not care for the **selectedLineVirtualId** which represents the selected line without a package. To avoid this and make it so that only one line is selected even if they have different package, we now set the corresponding value to false to unselect the other line in all situation. This is basically how it's done in https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L1202-L1208 to unselect every line regardless of packages. opw-6266203 Forward-Port-Of: odoo/enterprise#125703 Forward-Port-Of: odoo/enterprise#122038
This update ensures the Ecuador electronic invoicing module installs with the payment dependency it needs. It prevents automated installation tests from failing when optional modules are skipped, improving release stability without changing day-to-day user behavior.
Original PR description
Runbot test would fail when running with `--skip-auto-install` due to the file l10n_ec_edi/views/withhold_portal_templates.xml referencing something that didn't exist as `account_payment` wasn't installed. Element `<xpath expr="//div[@name='invoice_paid_badge']">` cannot be located in parent view Reproduction step: odoo/odoo-bin --addons-path odoo/addons,odoo/odoo/addons,enterprise,design-themes -d oes_test --stop-after-init --log-level=test --max-cron-threads=0 -i l10n_ec_edi --skip-auto-install runbot-[237864](https://runbot.odoo.com/odoo/error/237864)
This fix reverts a module dependency change in the Helpdesk Knowledge website integration because dependency changes are not allowed in stable releases. It helps keep the stable version predictable and reduces the risk of unintended installation or upgrade behavior.
Original PR description
Changes to depends are not allowed in stable Merge through saas-19.1 https://github.com/odoo/enterprise/pull/126260 Forward-Port-Of: odoo/enterprise#126892
**PROBLEM** When using fixed tax not affecting the base on line with discount, the xml generated is invalid and refused by peppol. **STEP TO REPRODUCE** 1. Install l10n_be. 2. Create an invoice with the following line: - qty: 2, price_unit: 100, discount: 10%, taxes: 21% + fixed tax 1€ - qty: -2, price_unit: 0, taxes: fixed tax 1€ 3. Generate an xml, and try validating it on peppol. 4. The validation fails with the error: [BR-27]-The Item net price (BT-146) shall NOT be negative.
Original PR description
**PROBLEM** When using fixed tax not affecting the base on line with discount, the xml generated is invalid and refused by peppol. **STEP TO REPRODUCE** 1. Install l10n_be. 2. Create an invoice with…
**PROBLEM** When using fixed tax not affecting the base on line with discount, the xml generated is invalid and refused by peppol. **STEP TO REPRODUCE** 1. Install l10n_be. 2. Create an invoice with the following line: - qty: 2, price_unit: 100, discount: 10%, taxes: 21% + fixed tax 1€ - qty: -2, price_unit: 0, taxes: fixed tax 1€ 3. Generate an xml, and try validating it on peppol. 4. The validation fails with the error: [BR-27]-The Item net price (BT-146) shall NOT be negative. **CAUSE** Fixed tax not affecting the base of other tax are dispatched into new base lines and then merged into one line per fixed tax. The new base lines they are dispatched to are created as a copy of the line they originated from. It means we copy the discount from the original lines. The fixed tax amount is the unit price of each new base lines. When reducing the base lines into one line, we take the unit prices of the line, and apply the discount to the unit price. But, since the unit price is the fixed tax amount, and fixed tax are not affected by discounts, we shouldn't apply discount. **PROBLEM 2** fixed division by 0 traceback when the aggregation of invoice lines is 0 **STEP TO REPRODUCE** 1. Install l10n_be. 2. Create the following invoice: - qty: 1, unit_price: 100, tax:0% + fixed tax 1€, set an analytic distribution account - qty: -1, unit_price: 50, tax:0% + fixed tax 1€, set the same analytic distribution account 3. Send the invoice to peppol. 4. A division by 0 should occur. opw-6388219 Forward-Port-Of: odoo/odoo#276945
Before this commit: The info, 'You can choose how you want us to send your invoices, and with which electronic format.' was never visible because `invoice_edi_format` is always None. After this commit: Update condition from `invoice_edi_format` to `invoice_edi_formats` to make condition correct and will display info if there are multiple invoice_sending_methods and at-least one edi format. Forward-Port-Of: odoo/odoo#278870
Original PR description
Before this commit: The info, 'You can choose how you want us to send your invoices, and with which electronic format.' was never visible because `invoice_edi_format` is always None. After this commit: Update condition from `invoice_edi_format` to `invoice_edi_formats` to make condition correct and will display info if there are multiple invoice_sending_methods and at-least one edi format. Forward-Port-Of: odoo/odoo#278870
## Issue When generating an invoice for a service product with an invoicing policy based on timesheets, the amount of hours invoiced is wrong if there exists a credit note linked to that SO. ## Steps to reproduce 1. Install *Sales Timesheet* (`sale_timesheet`) 2. Create a Product P - Product Type: Service - Create on Order: Task - Project: Any project - Invoicing Policy: Based on Timesheets 3. Create a SO - Any Customer - Product P (any quantity) - Confi
Original PR description
## Issue When generating an invoice for a service product with an invoicing policy based on timesheets, the amount of hours invoiced is wrong if there exists a credit note linked to that SO. ## Steps…
## Issue
When generating an invoice for a service product with an invoicing policy based on timesheets, the amount of hours invoiced is wrong if there exists a credit note linked to that SO.
## Steps to reproduce
1. Install *Sales Timesheet* (`sale_timesheet`)
2. Create a Product P
- Product Type: Service
- Create on Order: Task
- Project: Any project
- Invoicing Policy: Based on Timesheets
3. Create a SO
- Any Customer
- Product P (any quantity)
- Confirm the SO
4. In the created task, add a timesheet entry
- Date: Today
- Time Spent: 10:00 (10 hours)
5. Create and confirm the invoice for the SO
6. Create a Credit Note from the invoice, set the quantity to 4 hours, and confirm it
7. From the created task, add a second timesheet entry
- Date: Any future date (e.g., today + 7)
- Time Spent: 15:00 (15 hours)
8. Create a second invoice, but set a Timesheets Period that only covers the second timesheet entry
9. **The quantity on the newly created invoice is 9 hours, even though we're clearly trying to invoice the 15 hours from the second timesheet entry.**
## Cause
The second invoice is impacted by the credit note generated from the first one. When generating that second invoice, the [`_recompute_qty_to_invoice`](https://github.com/odoo/odoo/blob/0512ebd4c8cc277fdb4fbe0f57619a0bd61192c2/addons/sale_timesheet/models/sale_order_line.py#L149) method incorrectly computes the amount to invoice by taking into account `account.analytic.line` from outside the provided range.
The delivered quantity is correctly calculated by taking into account the provided range (through the `start_date` and `end_date` added to the domain passed to `_get_delivered_quantity_by_analytic`:
https://github.com/odoo/odoo/blob/0512ebd4c8cc277fdb4fbe0f57619a0bd61192c2/addons/sale_timesheet/models/sale_order_line.py#L176-L180
But then, for each `sale.order.line`, we look at the related `account.analytic.line` without taking into account the provided dates, which leads to lines outside of the range impacting the invoice.
https://github.com/odoo/odoo/blob/0512ebd4c8cc277fdb4fbe0f57619a0bd61192c2/addons/sale_timesheet/models/sale_order_line.py#L182-L193
In the example described in the *Steps to reproduce*, we start with a (correct) amount delivered of 15.0, we find two `invoice_lines_to_calculate` (the invoice of 10 hours, and the credit note of 4 hours), which leads to the quantity to invoice being set to `15 - (-4 + 10) = 9`. This seems like an odd behavior as it:
- doesn't invoice all the hours within the provided range (15 hours within the range, and we're only invoicing 9)
- doesn't invoice **all** the hours left to be invoiced (6 hours are already invoiced, 25 should be in total, and we're invoicing 9)
opw-6373870
Forward-Port-Of: odoo/odoo#277727Issue: Every change of the selected order makes the PoS call `pos.config.update_customer_display`, which publishes the order on the bus for the customer display paired with this browser. The device uuid identifying that pairing is only generated when the customer display dialog is opened, so a PoS whose customer display was never opened sends `device_uuid: null` and the server publishes on `UPDATE_CUSTOMER_DISPLAY-null`, a channel nobody can listen to. Steps to reproduce: Open a PoS session
Original PR description
Issue: Every change of the selected order makes the PoS call `pos.config.update_customer_display`, which publishes the order on the bus for the customer display paired with this browser. The device…
Issue: Every change of the selected order makes the PoS call `pos.config.update_customer_display`, which publishes the order on the bus for the customer display paired with this browser. The device uuid identifying that pairing is only generated when the customer display dialog is opened, so a PoS whose customer display was never opened sends `device_uuid: null` and the server publishes on `UPDATE_CUSTOMER_DISPLAY-null`, a channel nobody can listen to. Steps to reproduce: Open a PoS session, never open the customer display, and add a product to an order. Current behaviour: An rpc is sent for each change of the order, and each of them ends up as a bus notification that no customer display can ever receive. Expected behaviour: Nothing is sent as long as no customer display was ever opened. Solution: Skip the rpc while no device uuid exists. A customer display opened in the same browser as the PoS is served by the BroadcastChannel, which is unaffected. task-6408513 Forward-Port-Of: odoo/odoo#277687
The bugfix introduced in https://github.com/odoo/odoo/commit/01d11a770f89c391f7c6a2c46a3d770d10afb428 made it so that "personal" outgoing mail servers are blocked/ignored from being used in email marketing as dedicated servers. In doing so, it missed the fact that while in *Email Marketing > Settings*, the "Dedicated Server" picker now correctly ignores personal OMS entries, the selection widget for `mail_server_id` in `view_mail_mass_mailing_form` still let's you manually select a OMS with a
Original PR description
The bugfix introduced in https://github.com/odoo/odoo/commit/01d11a770f89c391f7c6a2c46a3d770d10afb428 made it so that "personal" outgoing mail servers are blocked/ignored from being used in email…
The bugfix introduced in https://github.com/odoo/odoo/commit/01d11a770f89c391f7c6a2c46a3d770d10afb428 made it so that "personal" outgoing mail servers are blocked/ignored from being used in email marketing as dedicated servers.
In doing so, it missed the fact that while in *Email Marketing > Settings*, the "Dedicated Server" picker now correctly ignores personal OMS entries, the selection widget for `mail_server_id` in `view_mail_mass_mailing_form` still let's you manually select a OMS with an owner set. As there is not warning or an explicit error, this can lead to accidental miss configurations on an email marketing campaign, where the selected OMS will be actually ignored by the backend.
To align the changes introduced by the bugfix, we add a search domain to the selection field, so that only OMS with `('owner_user_id', '=', False)` will be presented as a choice.
OPW-6388562
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#278595In this commit: - When only one preset remains available after filtering table identifier in self-order mode, automatically select it and skip the preset selection page. - This avoids showing a location selection page when there is no actual choice available to the customer. Task:6217791 Enterprise PR : https://github.com/odoo/enterprise/pull/122979 Forward-Port-Of: odoo/odoo#274301
Original PR description
In this commit: - When only one preset remains available after filtering table identifier in self-order mode, automatically select it and skip the preset selection page. - This avoids showing a location selection page when there is no actual choice available to the customer. Task:6217791 Enterprise PR : https://github.com/odoo/enterprise/pull/122979 Forward-Port-Of: odoo/odoo#274301
Repro steps: 1) Create an invoice 2) Activate auto post (monthly for example) 3) Confirm the invoice, a new draft invoice will be created 4) Reset to draft 5) Confirm again Problem: A second draft would be created, and next period, 2 invoices would be confirmed Fix: This commit deletes the next auto post recurrence of an invoice, if that next recurrence is in draft, and the invoice is being set to draft. It also prevents creating a recurrence at a date if there is already an exi
Original PR description
Repro steps: 1) Create an invoice 2) Activate auto post (monthly for example) 3) Confirm the invoice, a new draft invoice will be created 4) Reset to draft 5) Confirm again Problem: A second draft would be created, and next period, 2 invoices would be confirmed Fix: This commit deletes the next auto post recurrence of an invoice, if that next recurrence is in draft, and the invoice is being set to draft. It also prevents creating a recurrence at a date if there is already an existing recurrent move on that date. task-6311219 Forward-Port-Of: odoo/odoo#279159
Description of the issue/feature this PR addresses: Mail server ports are identifiers rather than quantities. The incoming and outgoing mail server views use the unsupported `format` option, so locale-based integer formatting remains enabled. Steps to reproduce: 1. Enable developer mode. 2. Go to Settings > Technical > Email > Outgoing Mail Servers. 3. Create a server and set SMTP Port to `8069`. 4. Move focus away from the field. 5. The same issue occurs on an Incomin
Original PR description
Description of the issue/feature this PR addresses: Mail server ports are identifiers rather than quantities. The incoming and outgoing mail server views use the unsupported `format` option, so…
Description of the issue/feature this PR addresses: Mail server ports are identifiers rather than quantities. The incoming and outgoing mail server views use the unsupported `format` option, so locale-based integer formatting remains enabled. Steps to reproduce: 1. Enable developer mode. 2. Go to Settings > Technical > Email > Outgoing Mail Servers. 3. Create a server and set SMTP Port to `8069`. 4. Move focus away from the field. 5. The same issue occurs on an Incoming Mail Server with a port such as `10143`. Current behavior before PR: Ports are displayed with thousands separators, e.g. `8,069` and `10,143`. Desired behavior after PR is merged: Mail server ports remain unformatted, e.g. `8069` and `10143`. Fixes #275937 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr "As a recent Computer Engineering graduate, I made my first open-source contribution to Odoo." :) Forward-Port-Of: odoo/odoo#278329
A user with own sales permissions won't be able to change the task partner when that task has a timesheet configured. Description of the issue/feature this PR addresses: - With a user with bare sales permissions (own sales) go to a task with timesheets and a sale order linked to it - Try to change the Customer for the task and save Current behavior before PR: <img width="1148" height="308" alt="image" src="https://github.com/user-attachments/assets/f0ccd25c-757b-455f-be36-68599de18c
Original PR description
A user with own sales permissions won't be able to change the task partner when that task has a timesheet configured. Description of the issue/feature this PR addresses: - With a user with bare sales permissions (own sales) go to a task with timesheets and a sale order linked to it - Try to change the Customer for the task and save Current behavior before PR: <img width="1148" height="308" alt="image" src="https://github.com/user-attachments/assets/f0ccd25c-757b-455f-be36-68599de18cd3" /> Desired behavior after PR is merged: No access error cc @moduon MT-15215 OPW-6364376 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273916
Steps to reproduce: 1) Install hr_holidays & hr_attendance. 2) Enable "Display Extra Hours" & "Absence Management" in the Attendance app settings. 3) Make a new employee, in the form view click the "+" button to make a new hr version record for this employee. 4) Set the date to be the first of the last month. 5) In the Attendance app -> New -> Select the new employee. 6) Select the check in and out dates to be from last month, edit the times such that the time worked is between 7 and 8 h
Original PR description
Steps to reproduce: 1) Install hr_holidays & hr_attendance. 2) Enable "Display Extra Hours" & "Absence Management" in the Attendance app settings. 3) Make a new employee, in the form view click the…
Steps to reproduce: 1) Install hr_holidays & hr_attendance. 2) Enable "Display Extra Hours" & "Absence Management" in the Attendance app settings. 3) Make a new employee, in the form view click the "+" button to make a new hr version record for this employee. 4) Set the date to be the first of the last month. 5) In the Attendance app -> New -> Select the new employee. 6) Select the check in and out dates to be from last month, edit the times such that the time worked is between 7 and 8 hours (ex 9:00am to 4:55pm). 7) In the Attendance app -> Reporting -> Attendances -> the test employee should have a negative value for "Worked Extra Hours" 8) Create a new time off type, enable "Deduct Extra Hours" & disable "Requires Allocation" use hours as the Unit of measure. 9) Open the time off smart button menu from the test employee's form view. Issue) The value seen in the report from step 7 is not the same as what the user sees in the dashboard. Notes) This issue can occur when an employee scheduled to work for 8 hours a day only clocks in for 7:55 hours leading to a negative extra time. The back-end has the correct value stored and sends it to the browser. The issue occurs because the JavaScript function that converts the decimal number of hours into a string (9.5 -> "9:30") does not work with negative input. This PR resolves that issue. opw-6417543 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
**PROBLEM** Before this PR, there was no way to handle invoices sent to clients depending from a JST/LGU (local government unit). This PR add support for it. opw-6095581 Forward-Port-Of: odoo/odoo#280085 Forward-Port-Of: odoo/odoo#260367
Original PR description
**PROBLEM** Before this PR, there was no way to handle invoices sent to clients depending from a JST/LGU (local government unit). This PR add support for it. opw-6095581 Forward-Port-Of: odoo/odoo#280085 Forward-Port-Of: odoo/odoo#260367
Currently, a transfer is marked as 'Printed' only when the 'Picking Operations' report is printed using the Print button in the 'ready' state. If the same report is printed from the actions (gear) menu, the transfer is not marked as printed. This PR ensures that printing the 'Picking Operations' report from the actions menu also marks the transfer as 'Printed'. **Steps to reproduce:** - Install the stock module. - Open the Transfers list view. - Add custom group for 'Printed'. - Open a
Original PR description
Currently, a transfer is marked as 'Printed' only when the 'Picking Operations' report is printed using the Print button in the 'ready' state. If the same report is printed from the actions (gear)…
Currently, a transfer is marked as 'Printed' only when the 'Picking Operations' report is printed using the Print button in the 'ready' state. If the same report is printed from the actions (gear) menu, the transfer is not marked as printed. This PR ensures that printing the 'Picking Operations' report from the actions menu also marks the transfer as 'Printed'. **Steps to reproduce:** - Install the stock module. - Open the Transfers list view. - Add custom group for 'Printed'. - Open a transfer in the 'ready' state and print the 'Picking Operations' report using the Print button. Notice that the transfer is marked as 'Printed'. - Open another transfer in the 'ready' state and print the 'Picking Operations' report from the actions menu. - Observe that the transfer is not marked as Printed. The same issue occurs when printing it from list view. **Expected behavior:** A transfer in the 'ready' state should be marked as Printed whenever the 'Picking Operations' report is printed, regardless of whether it is triggered from the 'Print' button or the actions menu. close #235129 Forward-Port-Of: odoo/odoo#276582
Before this commit, turning the camera on during a call could leave the camera off in every member's UI, including the local user's own tile, while the video was already being sent. This happens because toggleVideo awaits network.updateUpload before updateAndBroadcast, and updateUpload waits on the ready promise of every peer. A single member whose handshake never completes holds isCameraOn and isScreenSharingOn for everyone. This commit fixes the issue by broadcasting the state first and
Original PR description
Before this commit, turning the camera on during a call could leave the camera off in every member's UI, including the local user's own tile, while the video was already being sent. This happens because toggleVideo awaits network.updateUpload before updateAndBroadcast, and updateUpload waits on the ready promise of every peer. A single member whose handshake never completes holds isCameraOn and isScreenSharingOn for everyone. This commit fixes the issue by broadcasting the state first and awaiting the upload after. Note that updateUpload sends its info snapshot to the peers synchronously, so they still learn the new track. Back-port of https://github.com/odoo/odoo/pull/279106 Forward-Port-Of: odoo/odoo#280301 Forward-Port-Of: odoo/odoo#280014
By default event notifications are configured with positive integers to state how many minutes/hours/days they should be triggered before an event starts. This works fine in within Odoo. But in an ICS file a TRIGGER with such positive integer means it starts after the event. For example ICS file generated by Odoo contains TRIGGER;related=START:PT15M but it should be negative: TRIGGER;related=START:-PT15M (note the minus) in order to trigger before the event. See [here](https://icalendar.org/iCal
Original PR description
By default event notifications are configured with positive integers to state how many minutes/hours/days they should be triggered before an event starts. This works fine in within Odoo. But in an ICS file a TRIGGER with such positive integer means it starts after the event. For example ICS file generated by Odoo contains TRIGGER;related=START:PT15M but it should be negative: TRIGGER;related=START:-PT15M (note the minus) in order to trigger before the event. See [here](https://icalendar.org/iCalendar-RFC-5545/3-8-6-3-trigger.html) for reference. Current behavior before PR: The reminder is triggered AFTER the event start Desired behavior after PR is merged: The reminder is triggered BEFORE the event start Closes #245052. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274744
Steps to reproduce 1. Go to Manufacturing > Configuration > Settings and enable By-Products 2. Go to Inventory > Configuration > Locations, find the location with type Production and set the Cost of Production account 3. Go to Inventory > Configuration > Product Categories and set the costing method to Standard Price and Inventory Valuation to Perpetual (at invoicing) 4. Set the finished product and byproduct as Storable with a non-zero Cost 5. Create a BoM with a component and a by
Original PR description
Steps to reproduce 1. Go to Manufacturing > Configuration > Settings and enable By-Products 2. Go to Inventory > Configuration > Locations, find the location with type Production and set the Cost of…
Steps to reproduce 1. Go to Manufacturing > Configuration > Settings and enable By-Products 2. Go to Inventory > Configuration > Locations, find the location with type Production and set the Cost of Production account 3. Go to Inventory > Configuration > Product Categories and set the costing method to Standard Price and Inventory Valuation to Perpetual (at invoicing) 4. Set the finished product and byproduct as Storable with a non-zero Cost 5. Create a BoM with a component and a byproduct with a Cost Share % assigned 6. Create and complete a manufacturing order 7. Check the journal entries of the MO: the byproduct entry shows $0 Issue Standard-cost byproduct moves have no price_unit set in either code path of _cal_price, so their journal entries always show $0. When the finished product is standard cost, _cal_price returns early at https://github.com/odoo/odoo/blob/55221db559cda1c61229eecf8493f5fbaee5cd50/addons/mrp_account/models/mrp_production.py#L66-L68 without iterating byproducts at all, so no price_unit is ever set on them. When the finished product is FIFO/AVCO, the byproduct loop at https://github.com/odoo/odoo/blob/55221db559cda1c61229eecf8493f5fbaee5cd50/addons/mrp_account/models/mrp_production.py#L83-L84 only sets price_unit for FIFO/AVCO byproducts. Standard byproducts are skipped, giving them $0 even though their cost_share was already deducted from the finished product, making value disappear from inventory entirely. For standard-cost products the MO has no influence on their value — they always use the standard_price from the product form, regardless of cost_share. Solution In the early-return branch, iterate byproducts: standard ones get standard_price, FIFO/AVCO ones get total_cost * cost_share. In the FIFO/AVCO branch, add the same standard_price fallback so standard byproducts are no longer left at $0 when their cost_share is set. opw-6020065 Forward-Port-Of: odoo/odoo#257472
A user with role Inventory/User cannot validate the dropship of a product with an Average Cost (AVCO) Costing Method Steps to reproduce: 1. Install sale_management, stock_dropshipping and stock_landed_costs module 2. Go to Sales > Configuration > Categories and change Furniture / Office's Costing Method to Average Cost (AVCO) 3. Go to Settings > Users and set Marc Demo's role on Purchase to User 3. Log in as Marc Demo 4. Create and confirm a quotation for customer Acme Corporation with p
Original PR description
A user with role Inventory/User cannot validate the dropship of a product with an Average Cost (AVCO) Costing Method Steps to reproduce: 1. Install sale_management, stock_dropshipping and…
A user with role Inventory/User cannot validate the dropship of a product with an Average Cost (AVCO) Costing Method Steps to reproduce: 1. Install sale_management, stock_dropshipping and stock_landed_costs module 2. Go to Sales > Configuration > Categories and change Furniture / Office's Costing Method to Average Cost (AVCO) 3. Go to Settings > Users and set Marc Demo's role on Purchase to User 3. Log in as Marc Demo 4. Create and confirm a quotation for customer Acme Corporation with product Large Cabinet (Dropship route and AVCO costing method) 5. Go to the related purchase order and confirm it 6. Go to the related dropship and validate it 7. An access error is raised Issue: Validating a dropship recomputes the cost of the product and reads `stock.valuation.adjustment.lines` https://github.com/odoo/odoo/blob/cb7b3de6cea07464bcadd1325f52533d34ce09bc/addons/stock_landed_costs/models/stock_move.py#L11 But only Inventory/Administrator have read access to these records https://github.com/odoo/odoo/blob/cb7b3de6cea07464bcadd1325f52533d34ce09bc/addons/stock_landed_costs/security/ir.model.access.csv#L4 Solution: Call `_get_landed_cost` with `.sudo()` in order to update the cost even though the user has no landed costs access opw-6366844 Forward-Port-Of: odoo/odoo#276285
purpose: 1- We should have a consistent way to compute `_gantt_unavailability` of employees in time off and attendance. Currently, some cases have inconsistent behavior such as out of contract days, flexible and fully flexibe employees. 2- In time off calendar view, if the employee does not have a contract at all, the current working schedule will appear in the calendar and it will not be greyed out. This is inconsistent with the behavior of the attendance application. Fix: 1: - implemente
Original PR description
purpose: 1- We should have a consistent way to compute `_gantt_unavailability` of employees in time off and attendance. Currently, some cases have inconsistent behavior such as out of contract days,…
purpose:
1- We should have a consistent way to compute `_gantt_unavailability` of employees in time off and attendance. Currently, some cases have inconsistent behavior such as out of contract days, flexible and fully flexibe employees. 2- In time off calendar view, if the employee does not have a contract at all, the current working schedule will appear in the calendar and it will not be greyed out. This is inconsistent with the behavior of the attendance application.
Fix:
1:
- implemented `_get_employee_unavailable_intervals` in employee model to be used in both time off and attendance.
- more optimized than the old implementation in time off as it calls `_work_intervals_batch` once per calendar instead of calling it for each contract in `_unavailable_intervals_batch`
- greys out "out of contract" periods
- for flexible and fully flexible employees, the whole period is considered available except leave periods
- made `_get_calendar_periods` use version date start instead of contract date start and corrected a bug in tz conversion 2:
- made `_get_unusual_days` return True for all the days outside of contracts for the employee instead of not returning anything for them or getting values from the working schedule of the employee (means that they will be greyed out in the callendar view) and added a test for it
task-id: 5473055
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#258038Problem: The `product_label_section_and_note_field` widget ignores the `no_open` option in list views. The `m2oProps` getter overrides the framework's native `p.canOpen` property, hardcoding the clickable state based purely on readonly status. Purpose: Ensure the widget respects standard framework options by the `p.canOpen` with the business logic, restoring the ability to disable record navigation. Steps to Reproduce on Runbot: - Go to Purchase app and open a quotation. - Open Odoo St
Original PR description
Problem: The `product_label_section_and_note_field` widget ignores the `no_open` option in list views. The `m2oProps` getter overrides the framework's native `p.canOpen` property, hardcoding the clickable state based purely on readonly status. Purpose: Ensure the widget respects standard framework options by the `p.canOpen` with the business logic, restoring the ability to disable record navigation. Steps to Reproduce on Runbot: - Go to Purchase app and open a quotation. - Open Odoo Studio. - Click on the product table and select "Edit list view". - Click on the product column. - On the sidebar, go to properties and activate "Disable opening". - Close Studio and click the product name on a line. - The form view action is triggered. opw-6422065 Forward-Port-Of: odoo/odoo#279221
Previously, we did not prevent FRCTC from registering through Peppol, even though FRCTC is not supported in Peppol. French companies could attempt to register in Peppol with FRCTC, which caused many errors. task-6421930 Forward-Port-Of: odoo/odoo#278782
Original PR description
Previously, we did not prevent FRCTC from registering through Peppol, even though FRCTC is not supported in Peppol. French companies could attempt to register in Peppol with FRCTC, which caused many errors. task-6421930 Forward-Port-Of: odoo/odoo#278782
Before this commit, this test was failing non-deterministically on on some machines: ``` show banner for new message after thread was read from another device ``` With the following error: ``` Error: Failed to find 1 of ".o-mail-Thread-banner:has(:text('1 new message'))" (Timeout of 3 seconds). Found 0 instead. ``` This happens because while the message list has 20 messages, each message is 1-line long. That means on many monitors the bottom of conversation is visible and thus it c
Original PR description
Before this commit, this test was failing non-deterministically on on some machines:
```
show banner for new message after thread was read from another device
```
With the following error:
```
Error: Failed to find 1 of ".o-mail-Thread-banner:has(:text('1 new message'))" (Timeout of 3 seconds). Found 0 instead.
```
This happens because while the message list has 20 messages, each message is 1-line long. That means on many monitors the bottom of conversation is visible and thus it can mark as read automatically the conversation. When this happens the banner is removed, thus the last step would fail.
This commit fixes the issue by making each message body bigger, so that this is very unlikely to see the bottom of message list, therefore avoiding the auto-mark as read from reaching the bottom of conversation.
Forward-Port-Of: odoo/odoo#280103**Steps to reproduce:** - Go to any view where you can send mails (eg sale orders) - Send a first mail to multiple recipients so they are added automatically on the next mail. - Open a new mail, confirm that the recipients are present, add a selectable attachment (eg a PDF), then click on it. - Remove any amount of recipients then send the mail. - You will see that the recipients are added back and the mail is sent to them. **Behavior:** Currently whenever a user clicks on an attachment
Original PR description
**Steps to reproduce:** - Go to any view where you can send mails (eg sale orders) - Send a first mail to multiple recipients so they are added automatically on the next mail. - Open a new mail,…
**Steps to reproduce:**
- Go to any view where you can send mails (eg sale orders)
- Send a first mail to multiple recipients so they are added automatically on the next mail.
- Open a new mail, confirm that the recipients are present, add a selectable attachment (eg a PDF), then click on it.
- Remove any amount of recipients then send the mail.
- You will see that the recipients are added back and the mail is sent to them.
**Behavior:**
Currently whenever a user clicks on an attachment in a mail composer, the systems considers that the user might be trying
to leave the page and will trigger an `urgentSave()`, and further down the line a `web_save()`.
The behavior when a web_save() is triggered is to create a record if there isnt currently one, and otherwise to write the modified values onto the record, using commands.
The recipients for the mail are added by default, which is represented by a list of `[4, id]`add commands, that will be written on the record created in the first `web_save`, however this list is not correctly emptied after the first `_save()`.
If the list is present within `this._changes` then it is correctly cleared, but in the case where no changes were made, the within `this._values['partner_ids']` still contains the commands.
So when we later assign `this.data = { ...this._values };`, `this.data['partner_ids']` now contains our uncleared list of commands.
https://github.com/odoo/odoo/blob/f3e407c6a58abd2ddba42f26fcbd1928da63cb63/addons/web/static/src/model/relational_model/record.js#L1222-L1230
And when we compute changes['partner_ids'] in our next iteration, we find ourselves with our command list again.
https://github.com/odoo/odoo/blob/f3e407c6a58abd2ddba42f26fcbd1928da63cb63/addons/web/static/src/model/relational_model/record.js#L1317-L1322
So when we then try to remove a recipient tag, the new delete command `[3, id]`
just gets canceled out with the already present add command.
And the `write()` in `web_save()` only writes add commands of already present partners, which doesn't do anything.
----
This commit adds a line to ensure commands inside `_values` are cleared
opw-6304713
Forward-Port-Of: odoo/odoo#278876### Steps to reproduce: - Create a product with a bom and 2 operations - Create an MO for 1 unit of that product - Confirm the MO - On the bom, delete the second operation and modify the first operation on anything else than the company, name or workcenter - Go back to the MO, click the "Update Bom" button > The second operation is not unlinked and the first operation is not updated ### Cause of the issue: The `action_update_bom` updates the move raws and operations of the MO via t
Original PR description
### Steps to reproduce: - Create a product with a bom and 2 operations - Create an MO for 1 unit of that product - Confirm the MO - On the bom, delete the second operation and modify the first…
### Steps to reproduce: - Create a product with a bom and 2 operations - Create an MO for 1 unit of that product - Confirm the MO - On the bom, delete the second operation and modify the first operation on anything else than the company, name or workcenter - Go back to the MO, click the "Update Bom" button > The second operation is not unlinked and the first operation is not updated ### Cause of the issue: The `action_update_bom` updates the move raws and operations of the MO via the `_link_bom`: https://github.com/odoo/odoo/blob/f66614193cce18f5a3298d03ce7e5f29d54f07e9/addons/mrp/models/mrp_production.py#L1214-L1218 For draft MO's all the work of these updates is done via the compute methods and by deleting all the records unrelevant to the new bom: https://github.com/odoo/odoo/blob/f66614193cce18f5a3298d03ce7e5f29d54f07e9/addons/mrp/models/mrp_production.py#L2603-L2626 And, in that case all the workorders that are not linked to an operation of the bom are expected to be deleted. However, when the MO is not in draft, the update of operations is expected to be performed here: https://github.com/odoo/odoo/blob/f66614193cce18f5a3298d03ce7e5f29d54f07e9/addons/mrp/models/mrp_production.py#L2647-L2664 However, since the operation of the bom has been deleted, the workorder that is expected to be deleted is not linked to any operation and hence does not satisfy the condition to be deleted: https://github.com/odoo/odoo/blob/f66614193cce18f5a3298d03ce7e5f29d54f07e9/addons/mrp/models/mrp_production.py#L2663-L2664 Concerning the non update of operations, it happens because the MO's operation are only updated on the three fields: `company_id`, `workcenter_id`, `name`: https://github.com/odoo/odoo/blob/31df5033e31c193b4576ef37dfbc5fc683817bc5/addons/mrp/models/mrp_production.py#L2647-L2664 https://github.com/odoo/odoo/blob/31df5033e31c193b4576ef37dfbc5fc683817bc5/addons/mrp/models/mrp_production.py#L2628-L2629 However, many other changes can and are actually relevant. ### Note: Prior to commit 80e6ed658fb43584bc2fad673ca40d9af6cf0ab6 operations were archived on boms rather than deleted: https://github.com/odoo/odoo/blob/4a5270218fe6fd7d30edb6d684b3340dc7423bab/addons/mrp/views/mrp_routing_views.xml#L53-L55 As such they would still be linked to an operation (but unrelated to the present values of the bom) and hence would fall into the condition of being unlinked from the MO. Since the bom operations are no longer archived there is no way to determine if an operation used to be linked to a bom and we therefore need to chose between deleting all operations unrelated to the present bom or to keep them all (when the MO has been confirmed). Starting from saas-19.1, the fix conflict with commit https://github.com/odoo/odoo/commit/5c4cf2e0fcc3ed5bef77380bb65f356c56b5dac4 That is, the `action_update_bom`, now replan's workorders: https://github.com/odoo/odoo/blob/3412253211daf13d50755fdce7edd9ed9c4400df/addons/mrp/models/mrp_production.py#L1207-L1217 However, the `_link_bom` now unlinks the obsolete and re-creates the still valid workorders (possibly unplanned). In particular, both the computation of `is_planned` and of the new `duration_expected` might differ from the expected checked in the `action_update_bom`. Note that to ensure everything goes as planned, we need to unlink the obsolete workorders before creating the new workorders which would be incorrectly replanned. Other than that, the check on the `duration_expected` in the `action_update_bom` needs to be updated accordingly. Enterprise: https://github.com/odoo/enterprise/pull/120709 opw-6285878 opw-6261738 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#269747
Microsoft issues a new refresh token on every access token refresh (rolling 90-day sliding window). The previous code discarded it, causing users to be forced to re-authenticate every 90 days once the original token expired. Closes #253543 Forward-Port-Of: odoo/odoo#276595 Forward-Port-Of: odoo/odoo#268284
Original PR description
Microsoft issues a new refresh token on every access token refresh (rolling 90-day sliding window). The previous code discarded it, causing users to be forced to re-authenticate every 90 days once the original token expired. Closes #253543 Forward-Port-Of: odoo/odoo#276595 Forward-Port-Of: odoo/odoo#268284