Daily updates from Odoo
Friday, July 31, 2026
266 changes
18 changes
Resolved issues and error corrections
With pos_hr enabled, the cash in/out popup uses the cashier's `work_contact_id` as partner for the `account.bank.statement.line`. When that partner is archived or not part of the limited partner loading, the relation cannot be resolved in the frontend and the statement line is created with `partner_id = False`. Deleting such a cash move then crashes in `delete_cash_in_out`: File ".../point_of_sale/models/pos_session.py", line 1877, in delete_cash_in_out action = cashier_name +
Original PR description
With pos_hr enabled, the cash in/out popup uses the cashier's `work_contact_id` as partner for the `account.bank.statement.line`. When that partner is archived or not part of the limited partner…
With pos_hr enabled, the cash in/out popup uses the cashier's `work_contact_id` as partner for the `account.bank.statement.line`. When that partner is archived or not part of the limited partner loading, the relation cannot be resolved in the frontend and the statement line is created with `partner_id = False`.
Deleting such a cash move then crashes in `delete_cash_in_out`:
File ".../point_of_sale/models/pos_session.py", line 1877, in delete_cash_in_out
action = cashier_name + ': ' + str(amount)
TypeError: unsupported operand type(s) for +: 'bool' and 'str'
Steps to reproduce:
- Enable "Multi Employees per Session" (pos_hr) on a PoS config
- Archive the work contact of an employee, or make sure it is not included in the limited partner loading
- Open a session, log in as that employee and register a cash in/out
- As a manager, delete the cash move from the cash move list => Traceback, the cash move cannot be deleted
opw-6389830
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#278462
Forward-Port-Of: odoo/odoo#276598[FIX] stock: fix user permission to edit lots Issue: An user with the Role/User that is Inventory/Administrator is unable to edit the custom Lot/Serial Steps to reproduce: 1. Take a user with Role/User 2. Assign them Inventory/Administrator 3. Log in as this user and create a product tracked by lots 4. Go to the Inventory tab and try editing the field Custom Lot/Serial Cause: Only Role/Administrator can create Ir.Sequence, therefore even if a Role/User is Inventory/Administrator tri
Original PR description
[FIX] stock: fix user permission to edit lots Issue: An user with the Role/User that is Inventory/Administrator is unable to edit the custom Lot/Serial Steps to reproduce: 1. Take a user with Role/User 2. Assign them Inventory/Administrator 3. Log in as this user and create a product tracked by lots 4. Go to the Inventory tab and try editing the field Custom Lot/Serial Cause: Only Role/Administrator can create Ir.Sequence, therefore even if a Role/User is Inventory/Administrator tries to create a new Ir.Sequence (ex: editing a custom Lot/Serial) it will still throw him an error as he is not Role/Administrator Fix: To avoid the permissions issue at the time of creation we use sudo to bypass the Role/User lack of permissions. opw-6269415 Forward-Port-Of: odoo/odoo#278453 Forward-Port-Of: odoo/odoo#268799
Stripe recommends connecting to a reader returned by the most recent discovery call. However, the POS Stripe interface discovered readers as soon as the Stripe Terminal object was created, during POS loading. This means a POS reload performed long before the first payment could populate `pos.discoveredReaders` with stale reader objects. If the first Stripe Terminal payment happens much later, the SDK may try to connect using outdated reader/credential state and fail with an expired Connection
Original PR description
Stripe recommends connecting to a reader returned by the most recent discovery call. However, the POS Stripe interface discovered readers as soon as the Stripe Terminal object was created, during POS loading. This means a POS reload performed long before the first payment could populate `pos.discoveredReaders` with stale reader objects. If the first Stripe Terminal payment happens much later, the SDK may try to connect using outdated reader/credential state and fail with an expired ConnectionToken. Move reader discovery to `connectReader()` so Odoo connects using fresh discovery results, and stop discovering readers eagerly when creating the Stripe Terminal instance. opw-6311626 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277765 Forward-Port-Of: odoo/odoo#276875
### Issue: When importing EDI documents such as Peppol files, Swiss VAT numbers may be formatted or unformatted When `base_vat` is installed, VAT is stored formatted in Odoo (e.g. `CHE-530.781.296 TVA`) If the format differs, the matching fails and a new partner is created at each import ### Cause: `_retrieve_partner` lacked Swiss-specific VAT normalization logic in `_get_country_specific_vat_variants`, causing it to miss formatted variants with language suffixes (`TVA`, `MWST`, `IVA`)
Original PR description
### Issue: When importing EDI documents such as Peppol files, Swiss VAT numbers may be formatted or unformatted When `base_vat` is installed, VAT is stored formatted in Odoo (e.g. `CHE-530.781.296…
### Issue: When importing EDI documents such as Peppol files, Swiss VAT numbers may be formatted or unformatted When `base_vat` is installed, VAT is stored formatted in Odoo (e.g. `CHE-530.781.296 TVA`) If the format differs, the matching fails and a new partner is created at each import ### Cause: `_retrieve_partner` lacked Swiss-specific VAT normalization logic in `_get_country_specific_vat_variants`, causing it to miss formatted variants with language suffixes (`TVA`, `MWST`, `IVA`) Even when the match succeeded, `_import_ubl_create_missing_customer` still compared VAT strings without stripping `-` and lang suffixes for CH partners, causing a false mismatch and triggering partner creation anyway ### Notes: The partner match improvement is backported from 18.3: https://github.com/odoo/odoo/commit/f1a5a3d72a26ee471d2ef1d8034136208b2bcebc The original fix was incomplete — it added `_get_country_specific_vat_variants` but missed the VAT comparison fix in `_import_ubl_create_missing_customer`, allowing the issue to persist after a successful match `base_vat` is required to get the fix fully working ### Steps to reproduce: - Install `account` and `base_vat` - Create a Vendor (Name: Test CH Vendor, Country: Switzerland, Tax ID: CHE-530.781.296 TVA) - Import a [Peppol Bill](https://github.com/user-attachments/files/27202997/CH_bill_to_import.xml) with VAT `CHE530781296TVA` Before the fix, a new partner is created instead of matching the existing one opw-6353387 Forward-Port-Of: odoo/odoo#279184 Forward-Port-Of: odoo/odoo#274398
Following the rework of payment provider states (cf. PR https://github.com/odoo/odoo/pull/249545), `_toggle_post_processing_cron` only checked for installed providers using `module_state in ('installed', 'to install')`. However, providers that are not linked to a specific module (such as custom providers or test providers) have `module_id = False`, which causes `module_state` to evaluate to `False`. As a result, setting up these providers left the post-processing cron inactive, causing `test
Original PR description
Following the rework of payment provider states (cf. PR https://github.com/odoo/odoo/pull/249545),
`_toggle_post_processing_cron` only checked for installed providers using `module_state in ('installed', 'to install')`.
However, providers that are not linked to a specific module (such as custom providers or test providers) have `module_id = False`, which causes `module_state` to evaluate to `False`. As a result, setting up these providers left the post-processing cron inactive, causing `test_installing_provider_activates_post_processing_cron` to fail.
This commit updates the search domain in
`_toggle_post_processing_cron()` to also include providers where `module_id = False`, matching the domain logic used in `_find_available_providers()`.
runbot-940173Taxes with SAF-T code 21 and 22 are not correct and needed modification where they should be set to 0% because: - The foreign supplier invoices without Norwegian VAT, so the invoice total shouldn't increase - You must still self-assess 25% VAT and report it - The 25% is booked as both output and input VAT simultaneously → net cash effect = 0 - Only the basis amount is reported in the VAT return (import boxes) task-6254727 Forward-Port-Of: odoo/odoo#278896 Forward-Port-Of: odoo/odoo#26751
Original PR description
Taxes with SAF-T code 21 and 22 are not correct and needed modification where they should be set to 0% because: - The foreign supplier invoices without Norwegian VAT, so the invoice total shouldn't increase - You must still self-assess 25% VAT and report it - The 25% is booked as both output and input VAT simultaneously → net cash effect = 0 - Only the basis amount is reported in the VAT return (import boxes) task-6254727 Forward-Port-Of: odoo/odoo#278896 Forward-Port-Of: odoo/odoo#267510
The mail.message/delete bus handler accessed selfMember?.seen_message_id.id with optional chaining only on selfMember, not on seen_message_id. When a member has never seen any message in a channel (seen_message_id is False), accessing .id threw 'TypeError: can't access property id, selfMember.seen_message_id is undefined', breaking message deletion for that user (e.g. deleting a message in a channel the user never opened. Add optional chaining on seen_message_id so the unread counter is simpl
Original PR description
The mail.message/delete bus handler accessed selfMember?.seen_message_id.id with optional chaining only on selfMember, not on seen_message_id. When a member has never seen any message in a channel (seen_message_id is False), accessing .id threw 'TypeError: can't access property id, selfMember.seen_message_id is undefined', breaking message deletion for that user (e.g. deleting a message in a channel the user never opened. Add optional chaining on seen_message_id so the unread counter is simply not decremented when no message has been seen yet. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279279 Forward-Port-Of: odoo/odoo#277417
Test `load dashboard that doesn't exist` sometimes fails because the test doesn't wait for the rpc to complete before checking the error message. This commit adds a wait for the next animation frame to ensure the rpc has completed before checking the error message. Runbot-940389 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/su
Original PR description
Test `load dashboard that doesn't exist` sometimes fails because the test doesn't wait for the rpc to complete before checking the error message. This commit adds a wait for the next animation frame to ensure the rpc has completed before checking the error message. Runbot-940389 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#279418
Follow-up to #247929, which limited `forever` recurrences to a 15-year horizon (`calendar.max_recurrence_years`) for *yearly* and *monthly* frequencies but left *weekly* and *daily* on the hard cap `MAX_RECURRENT_EVENT` (720), ignoring the parameter. A weekly `forever` event therefore always materializes 720 occurrences (~14 years) regardless of `calendar.max_recurrence_years`, and a daily one ignores the parameter too. This applies the year limit to weekly and daily as well, accounting for th
Original PR description
Follow-up to #247929, which limited `forever` recurrences to a 15-year horizon (`calendar.max_recurrence_years`) for *yearly* and *monthly* frequencies but left *weekly* and *daily* on the hard cap `MAX_RECURRENT_EVENT` (720), ignoring the parameter. A weekly `forever` event therefore always materializes 720 occurrences (~14 years) regardless of `calendar.max_recurrence_years`, and a daily one ignores the parameter too. This applies the year limit to weekly and daily as well, accounting for the number of selected weekdays and the interval, while still capping at `MAX_RECURRENT_EVENT`. Steps to reproduce: 1. Set `calendar.max_recurrence_years` to e.g. 2. 2. Create a weekly event repeating "forever". 3. Before: 720 occurrences (~14 years). After: ~106 (2 years). task / context: extends #247929. Forward-Port-Of: odoo/odoo#272615 Forward-Port-Of: odoo/odoo#270348
hash_sign has become very used all over the place, so more and more tokens depend on `database.secret`, increasing the impact of that secret needing one day to be rotated or being compromised. To avoid making `database.secret` a single point of failure, we would like `hash_sign` to support a custom secret supplied by caller. task-6391264 Forward-Port-Of: odoo/odoo#278256 Forward-Port-Of: odoo/odoo#276474
Original PR description
hash_sign has become very used all over the place, so more and more tokens depend on `database.secret`, increasing the impact of that secret needing one day to be rotated or being compromised. To avoid making `database.secret` a single point of failure, we would like `hash_sign` to support a custom secret supplied by caller. task-6391264 Forward-Port-Of: odoo/odoo#278256 Forward-Port-Of: odoo/odoo#276474
Steps to reproduce --- 1. Confirm a purchase order and receive it a few days later. 2. Open Purchase, Reporting, Purchase and add the "Effective Days To Arrival" measure. Observed: the value is counted from the line's scheduled date instead of the order date, and can even be negative when the scheduled date precedes the confirmation date. Issue --- The metric is meant to be the effective lead time, the number of days between the order confirmation and the actual receipt, falling back
Original PR description
Steps to reproduce --- 1. Confirm a purchase order and receive it a few days later. 2. Open Purchase, Reporting, Purchase and add the "Effective Days To Arrival" measure. Observed: the value is…
Steps to reproduce --- 1. Confirm a purchase order and receive it a few days later. 2. Open Purchase, Reporting, Purchase and add the "Effective Days To Arrival" measure. Observed: the value is counted from the line's scheduled date instead of the order date, and can even be negative when the scheduled date precedes the confirmation date. Issue --- The metric is meant to be the effective lead time, the number of days between the order confirmation and the actual receipt, falling back to the planned "days to receive" when nothing has been received yet according to [task](https://www.odoo.com/odoo/project/809/tasks/3691573). The query instead computes age(date_planned, COALESCE(date_done, date_order)), so once a receipt exists it returns date_planned - date_done (the gap between the scheduled date and the receipt) rather than date_done - date_order. https://github.com/odoo/odoo/blob/c06be48ce7277a667719fd756e0a1f63e91cda27/addons/purchase_stock/report/purchase_report.py#L20-L28 opw-6226523 Forward-Port-Of: odoo/odoo#279267 Forward-Port-Of: odoo/odoo#268843
Problem: Clicking an image padding option in Studio reports closes the dropdown, but the selected option is not applied. Cause: When editing inside an `iframe`, `unFocusEditable` is triggered on `focusin`, which runs `selection_leave_handlers` and closes the dropdown before the `click` event can propagate. Solution: Add `data-prevent-closing-overlay="true"` to the image padding dropdown, as done for other dropdowns, so it remains open until the click event is handled. Steps to reprod
Original PR description
Problem: Clicking an image padding option in Studio reports closes the dropdown, but the selected option is not applied. Cause: When editing inside an `iframe`, `unFocusEditable` is triggered on `focusin`, which runs `selection_leave_handlers` and closes the dropdown before the `click` event can propagate. Solution: Add `data-prevent-closing-overlay="true"` to the image padding dropdown, as done for other dropdowns, so it remains open until the click event is handled. Steps to reproduce: - Open a new report. - Add an image. - Select the image. - Open the padding dropdown. - Click a padding option. - Observe that the dropdown closes but the padding is not applied. task-6368964 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279408 Forward-Port-Of: odoo/odoo#276448
The test "show pulse effect on fullscreen mode only when another participant's camera is on" fails from time to time on runbot: the pulse never lands on the fullscreen button. The first rtc session of a channel posts a call notification message, whose new_message notification fetches channels_as_member. That response carries the rtc sessions with their server values, so when it lands after the mock remote turned the camera on, is_camera_on goes back to false. videoCountNotSelf drops to 0 and
Original PR description
The test "show pulse effect on fullscreen mode only when another participant's camera is on" fails from time to time on runbot: the pulse never lands on the fullscreen button. The first rtc session of a channel posts a call notification message, whose new_message notification fetches channels_as_member. That response carries the rtc sessions with their server values, so when it lands after the mock remote turned the camera on, is_camera_on goes back to false. videoCountNotSelf drops to 0 and its onUpdate sets promoteFullscreen to INACTIVE for good, as only a change of the count sets it back to ACTIVE. A real participant also stores is_camera_on on the server, so a fetch never brings outdated values back. Make the mock remote do the same. https://runbot.odoo.com/odoo/error/242050 Forward-Port-Of: odoo/odoo#279178
In the Italian localization, a bill should not be reset to draft once it has been sent to SDI. The exception is when the document was rejected or imported (0440cbab7a9cc183c7836fe58196799afdc00513). Steps to reproduce: - Create a vendor bill with l10n_it_edi enabled. - Send it to SDI. - The "Reset to Draft" button is still visible. opw-6350928 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273616
Original PR description
In the Italian localization, a bill should not be reset to draft once it has been sent to SDI. The exception is when the document was rejected or imported (0440cbab7a9cc183c7836fe58196799afdc00513). Steps to reproduce: - Create a vendor bill with l10n_it_edi enabled. - Send it to SDI. - The "Reset to Draft" button is still visible. opw-6350928 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273616
Clicking a Unit Cost in the stock report opens the Unit Cost History of that product. The action filters on `active_id`, which the cost cell fills with the id of the row that was clicked. That value was overwritten: the cell context was merged first and the context of the running action last, so the latter won. When the list comes from "Inventory at Date", that context carries the id of the `stock.quantity.history` record the wizard just created, which is not a product id at all. The history
Original PR description
Clicking a Unit Cost in the stock report opens the Unit Cost History of that product. The action filters on `active_id`, which the cost cell fills with the id of the row that was clicked. That value was overwritten: the cell context was merged first and the context of the running action last, so the latter won. When the list comes from "Inventory at Date", that context carries the id of the `stock.quantity.history` record the wizard just created, which is not a product id at all. The history then opens on whichever product happens to carry that id, and stays empty when none does. Steps to reproduce: - Inventory > Reporting > Stock, click a Unit Cost -> the history of that product opens, as expected - go back, click "Inventory at Date" and confirm - click that same Unit Cost -> another product's history opens, or an empty list opw-6391778 Forward-Port-Of: odoo/odoo#279116
**Issue:** `test_mail_template_dynamic_placeholder_tour` tour is failing sometimes with the following error: `Tour mail_template_dynamic_field_tour → Step Click on contact (trigger: div[name="model_id"] .ui-autocomplete). TypeError: Cannot read properties of undefined (reading 'click')` **Cause:** It happens that the element is not loaded yet after the delay and clicking on an undefined element triggers the error. **Solution:** Make sure to only click on the element when it's ready.
Original PR description
**Issue:** `test_mail_template_dynamic_placeholder_tour` tour is failing sometimes with the following error: `Tour mail_template_dynamic_field_tour → Step Click on contact (trigger: div[name="model_id"] .ui-autocomplete). TypeError: Cannot read properties of undefined (reading 'click')` **Cause:** It happens that the element is not loaded yet after the delay and clicking on an undefined element triggers the error. **Solution:** Make sure to only click on the element when it's ready. runbot-223306 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278983 Forward-Port-Of: odoo/odoo#277954
Documentation and clarification updates
Description of the issue/feature this PR addresses: Add the Odoo Corporate Contributor License Agreement for bobco GmbH and list the employees authorized to contribute on the company's behalf. Current behavior before PR: bobco GmbH does not yet have a corporate CLA in the Odoo repository. Desired behavior after PR is merged: The corporate CLA covers the listed bobco GmbH contributors. Approval and signature status: @philipbr explicitly approved the declaration as an authorized representat
Original PR description
Description of the issue/feature this PR addresses: Add the Odoo Corporate Contributor License Agreement for bobco GmbH and list the employees authorized to contribute on the company's behalf. Current behavior before PR: bobco GmbH does not yet have a corporate CLA in the Odoo repository. Desired behavior after PR is merged: The corporate CLA covers the listed bobco GmbH contributors. Approval and signature status: @philipbr explicitly approved the declaration as an authorized representative of bobco GmbH. The signatory line has been finalized as: `Philip Braun philip@braun.tf https://github.com/philipbr` --- The corporate CLA has been signed by Philip Braun, and the PR guidelines at www.odoo.com/submit-pr have been read. Forward-Port-Of: odoo/odoo#279348
Miscellaneous changes
The government has held off the `shipToGSTIN` changes until further notice. https://services.gst.gov.in/services/advisoryandreleases/read/668 Hence, this PR reverts those changes. task-6431622 ref - https://github.com/odoo/odoo/pull/266388 Forward-Port-Of: odoo/odoo#279421
Original PR description
The government has held off the `shipToGSTIN` changes until further notice. https://services.gst.gov.in/services/advisoryandreleases/read/668 Hence, this PR reverts those changes. task-6431622 ref - https://github.com/odoo/odoo/pull/266388 Forward-Port-Of: odoo/odoo#279421
25 changes
Resolved issues and error corrections
### Issue: When importing EDI documents such as Peppol files, Swiss VAT numbers may be formatted or unformatted When `base_vat` is installed, VAT is stored formatted in Odoo (e.g. `CHE-530.781.296 TVA`) If the format differs, the matching fails and a new partner is created at each import ### Cause: `_retrieve_partner` lacked Swiss-specific VAT normalization logic in `_get_country_specific_vat_variants`, causing it to miss formatted variants with language suffixes (`TVA`, `MWST`, `IVA`)
Original PR description
### Issue: When importing EDI documents such as Peppol files, Swiss VAT numbers may be formatted or unformatted When `base_vat` is installed, VAT is stored formatted in Odoo (e.g. `CHE-530.781.296…
### Issue: When importing EDI documents such as Peppol files, Swiss VAT numbers may be formatted or unformatted When `base_vat` is installed, VAT is stored formatted in Odoo (e.g. `CHE-530.781.296 TVA`) If the format differs, the matching fails and a new partner is created at each import ### Cause: `_retrieve_partner` lacked Swiss-specific VAT normalization logic in `_get_country_specific_vat_variants`, causing it to miss formatted variants with language suffixes (`TVA`, `MWST`, `IVA`) Even when the match succeeded, `_import_ubl_create_missing_customer` still compared VAT strings without stripping `-` and lang suffixes for CH partners, causing a false mismatch and triggering partner creation anyway ### Notes: The partner match improvement is backported from 18.3: https://github.com/odoo/odoo/commit/f1a5a3d72a26ee471d2ef1d8034136208b2bcebc The original fix was incomplete — it added `_get_country_specific_vat_variants` but missed the VAT comparison fix in `_import_ubl_create_missing_customer`, allowing the issue to persist after a successful match `base_vat` is required to get the fix fully working ### Steps to reproduce: - Install `account` and `base_vat` - Create a Vendor (Name: Test CH Vendor, Country: Switzerland, Tax ID: CHE-530.781.296 TVA) - Import a [Peppol Bill](https://github.com/user-attachments/files/27202997/CH_bill_to_import.xml) with VAT `CHE530781296TVA` Before the fix, a new partner is created instead of matching the existing one opw-6353387 Forward-Port-Of: odoo/odoo#279184 Forward-Port-Of: odoo/odoo#274398
With pos_hr enabled, the cash in/out popup uses the cashier's `work_contact_id` as partner for the `account.bank.statement.line`. When that partner is archived or not part of the limited partner loading, the relation cannot be resolved in the frontend and the statement line is created with `partner_id = False`. Deleting such a cash move then crashes in `delete_cash_in_out`: File ".../point_of_sale/models/pos_session.py", line 1877, in delete_cash_in_out action = cashier_name +
Original PR description
With pos_hr enabled, the cash in/out popup uses the cashier's `work_contact_id` as partner for the `account.bank.statement.line`. When that partner is archived or not part of the limited partner…
With pos_hr enabled, the cash in/out popup uses the cashier's `work_contact_id` as partner for the `account.bank.statement.line`. When that partner is archived or not part of the limited partner loading, the relation cannot be resolved in the frontend and the statement line is created with `partner_id = False`.
Deleting such a cash move then crashes in `delete_cash_in_out`:
File ".../point_of_sale/models/pos_session.py", line 1877, in delete_cash_in_out
action = cashier_name + ': ' + str(amount)
TypeError: unsupported operand type(s) for +: 'bool' and 'str'
Steps to reproduce:
- Enable "Multi Employees per Session" (pos_hr) on a PoS config
- Archive the work contact of an employee, or make sure it is not included in the limited partner loading
- Open a session, log in as that employee and register a cash in/out
- As a manager, delete the cash move from the cash move list => Traceback, the cash move cannot be deleted
opw-6389830
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#278462
Forward-Port-Of: odoo/odoo#276598`onClickValidate`'s signature changed to `onClickValidate(args = {})`, so passing `true` directly from the Viva app callback made `isForceValidate` silently resolve to `false` instead of `true`. The previous `validateOrder` override was also dead code, since that method moved off `PaymentScreen` to `PosStore` and so we now override `onClickValidate` instead.
Original PR description
`onClickValidate`'s signature changed to `onClickValidate(args = {})`, so passing `true` directly from the Viva app callback made `isForceValidate` silently resolve to `false` instead of `true`.
The previous `validateOrder` override was also dead code, since that method moved off `PaymentScreen` to `PosStore` and so we now override `onClickValidate` instead.[FIX] stock: fix user permission to edit lots Issue: An user with the Role/User that is Inventory/Administrator is unable to edit the custom Lot/Serial Steps to reproduce: 1. Take a user with Role/User 2. Assign them Inventory/Administrator 3. Log in as this user and create a product tracked by lots 4. Go to the Inventory tab and try editing the field Custom Lot/Serial Cause: Only Role/Administrator can create Ir.Sequence, therefore even if a Role/User is Inventory/Administrator tri
Original PR description
[FIX] stock: fix user permission to edit lots Issue: An user with the Role/User that is Inventory/Administrator is unable to edit the custom Lot/Serial Steps to reproduce: 1. Take a user with Role/User 2. Assign them Inventory/Administrator 3. Log in as this user and create a product tracked by lots 4. Go to the Inventory tab and try editing the field Custom Lot/Serial Cause: Only Role/Administrator can create Ir.Sequence, therefore even if a Role/User is Inventory/Administrator tries to create a new Ir.Sequence (ex: editing a custom Lot/Serial) it will still throw him an error as he is not Role/Administrator Fix: To avoid the permissions issue at the time of creation we use sudo to bypass the Role/User lack of permissions. opw-6269415 Forward-Port-Of: odoo/odoo#278453 Forward-Port-Of: odoo/odoo#268799
Stripe recommends connecting to a reader returned by the most recent discovery call. However, the POS Stripe interface discovered readers as soon as the Stripe Terminal object was created, during POS loading. This means a POS reload performed long before the first payment could populate `pos.discoveredReaders` with stale reader objects. If the first Stripe Terminal payment happens much later, the SDK may try to connect using outdated reader/credential state and fail with an expired Connection
Original PR description
Stripe recommends connecting to a reader returned by the most recent discovery call. However, the POS Stripe interface discovered readers as soon as the Stripe Terminal object was created, during POS loading. This means a POS reload performed long before the first payment could populate `pos.discoveredReaders` with stale reader objects. If the first Stripe Terminal payment happens much later, the SDK may try to connect using outdated reader/credential state and fail with an expired ConnectionToken. Move reader discovery to `connectReader()` so Odoo connects using fresh discovery results, and stop discovering readers eagerly when creating the Stripe Terminal instance. opw-6311626 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277765 Forward-Port-Of: odoo/odoo#276875
Reading the `display_name` of a working schedule line of a 2 weeks calendar crashes: the compute reads `record.weektype` while the field is named `week_type`. ### Steps to reproduce - Switch a working schedule to a 2 weeks calendar. - Open one of its lines in a form view, e.g. with the `View Button` optional column in developer mode. opw-6427314 Forward-Port-Of: odoo/odoo#279194
Original PR description
Reading the `display_name` of a working schedule line of a 2 weeks calendar crashes: the compute reads `record.weektype` while the field is named `week_type`. ### Steps to reproduce - Switch a working schedule to a 2 weeks calendar. - Open one of its lines in a form view, e.g. with the `View Button` optional column in developer mode. opw-6427314 Forward-Port-Of: odoo/odoo#279194
The AutoComplete component wraps a text input that already renders its own suggestion dropdown, so the browser's native suggestions must stay out of the way. In 12/2024 in this commit [1] the input's autocomplete was switched from `off` to `new-password` on the premise that `off` is not respected by browsers. In 02/2025, in this commit [2] then made it the component default so many2x pickers stay clean. Chrome runs two independent suggestion mechanisms, and each attribute silences only
Original PR description
The AutoComplete component wraps a text input that already renders its own suggestion dropdown, so the browser's native suggestions must stay out of the way. In 12/2024 in this commit [1] the input's…
The AutoComplete component wraps a text input that already renders its own suggestion dropdown, so the browser's native suggestions must stay out of the way. In 12/2024 in this commit [1] the input's autocomplete was switched from `off` to `new-password` on the premise that `off` is not respected by browsers. In 02/2025, in this commit [2] then made it the component default so many2x pickers stay clean. Chrome runs two independent suggestion mechanisms, and each attribute silences only one of them: - `off` is ignored when the input has a name and Chrome holds autofill (address) data for it. - `new-password` is ignored when Chrome offers "frequently used values", i.e. the form-history dropdown. [3] So `new-password` does not always work. It only stays hidden while the field is ineligible for those suggestions. A field becomes eligible as soon as it gains an `id` and an associated `<label>`. On `saas-19.3` this is provable on commit [4] where adding a prefix icon gave the link popover URL input an `id` + `<label for>`, and the native dropdown resurfaced over the custom URL/page suggestions. This branch targets `saas-18.4`, where the regression is NOT reproducible because that URL input has no `id`/`label` yet. The fix is applied here anyway to avoid the gap that any later `label`/`id` addition re-exposes (as commit [4] proved), and the fix can be forward ported to `saas-19.3`. The website editor's URL field implements autocomplete without the `AutoComplete` component, so the default does not reach it. so `autocomplete="off"` is set directly on that input. [1]: https://github.com/odoo/odoo/commit/9c0f5612 [2]: https://github.com/odoo/odoo/commit/2980694b (opw-4551051) [3]: https://issues.chromium.org/issues/41163264#comment30 [4]: https://github.com/odoo/odoo/commit/2b4d04d1 (task-6034288) task-6370552 Forward-Port-Of: odoo/odoo#279203 Forward-Port-Of: odoo/odoo#277501
Steps to reproduce --- 1. Confirm a purchase order and receive it a few days later. 2. Open Purchase, Reporting, Purchase and add the "Effective Days To Arrival" measure. Observed: the value is counted from the line's scheduled date instead of the order date, and can even be negative when the scheduled date precedes the confirmation date. Issue --- The metric is meant to be the effective lead time, the number of days between the order confirmation and the actual receipt, falling back
Original PR description
Steps to reproduce --- 1. Confirm a purchase order and receive it a few days later. 2. Open Purchase, Reporting, Purchase and add the "Effective Days To Arrival" measure. Observed: the value is…
Steps to reproduce --- 1. Confirm a purchase order and receive it a few days later. 2. Open Purchase, Reporting, Purchase and add the "Effective Days To Arrival" measure. Observed: the value is counted from the line's scheduled date instead of the order date, and can even be negative when the scheduled date precedes the confirmation date. Issue --- The metric is meant to be the effective lead time, the number of days between the order confirmation and the actual receipt, falling back to the planned "days to receive" when nothing has been received yet according to [task](https://www.odoo.com/odoo/project/809/tasks/3691573). The query instead computes age(date_planned, COALESCE(date_done, date_order)), so once a receipt exists it returns date_planned - date_done (the gap between the scheduled date and the receipt) rather than date_done - date_order. https://github.com/odoo/odoo/blob/c06be48ce7277a667719fd756e0a1f63e91cda27/addons/purchase_stock/report/purchase_report.py#L20-L28 opw-6226523 Forward-Port-Of: odoo/odoo#279267 Forward-Port-Of: odoo/odoo#268843
Taxes with SAF-T code 21 and 22 are not correct and needed modification where they should be set to 0% because: - The foreign supplier invoices without Norwegian VAT, so the invoice total shouldn't increase - You must still self-assess 25% VAT and report it - The 25% is booked as both output and input VAT simultaneously → net cash effect = 0 - Only the basis amount is reported in the VAT return (import boxes) task-6254727 Forward-Port-Of: odoo/odoo#278896 Forward-Port-Of: odoo/odoo#26751
Original PR description
Taxes with SAF-T code 21 and 22 are not correct and needed modification where they should be set to 0% because: - The foreign supplier invoices without Norwegian VAT, so the invoice total shouldn't increase - You must still self-assess 25% VAT and report it - The 25% is booked as both output and input VAT simultaneously → net cash effect = 0 - Only the basis amount is reported in the VAT return (import boxes) task-6254727 Forward-Port-Of: odoo/odoo#278896 Forward-Port-Of: odoo/odoo#267510
The mail.message/delete bus handler accessed selfMember?.seen_message_id.id with optional chaining only on selfMember, not on seen_message_id. When a member has never seen any message in a channel (seen_message_id is False), accessing .id threw 'TypeError: can't access property id, selfMember.seen_message_id is undefined', breaking message deletion for that user (e.g. deleting a message in a channel the user never opened. Add optional chaining on seen_message_id so the unread counter is simpl
Original PR description
The mail.message/delete bus handler accessed selfMember?.seen_message_id.id with optional chaining only on selfMember, not on seen_message_id. When a member has never seen any message in a channel (seen_message_id is False), accessing .id threw 'TypeError: can't access property id, selfMember.seen_message_id is undefined', breaking message deletion for that user (e.g. deleting a message in a channel the user never opened. Add optional chaining on seen_message_id so the unread counter is simply not decremented when no message has been seen yet. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279279 Forward-Port-Of: odoo/odoo#277417
Test `load dashboard that doesn't exist` sometimes fails because the test doesn't wait for the rpc to complete before checking the error message. This commit adds a wait for the next animation frame to ensure the rpc has completed before checking the error message. Runbot-940389 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/su
Original PR description
Test `load dashboard that doesn't exist` sometimes fails because the test doesn't wait for the rpc to complete before checking the error message. This commit adds a wait for the next animation frame to ensure the rpc has completed before checking the error message. Runbot-940389 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#279418
Follow-up to #247929, which limited `forever` recurrences to a 15-year horizon (`calendar.max_recurrence_years`) for *yearly* and *monthly* frequencies but left *weekly* and *daily* on the hard cap `MAX_RECURRENT_EVENT` (720), ignoring the parameter. A weekly `forever` event therefore always materializes 720 occurrences (~14 years) regardless of `calendar.max_recurrence_years`, and a daily one ignores the parameter too. This applies the year limit to weekly and daily as well, accounting for th
Original PR description
Follow-up to #247929, which limited `forever` recurrences to a 15-year horizon (`calendar.max_recurrence_years`) for *yearly* and *monthly* frequencies but left *weekly* and *daily* on the hard cap `MAX_RECURRENT_EVENT` (720), ignoring the parameter. A weekly `forever` event therefore always materializes 720 occurrences (~14 years) regardless of `calendar.max_recurrence_years`, and a daily one ignores the parameter too. This applies the year limit to weekly and daily as well, accounting for the number of selected weekdays and the interval, while still capping at `MAX_RECURRENT_EVENT`. Steps to reproduce: 1. Set `calendar.max_recurrence_years` to e.g. 2. 2. Create a weekly event repeating "forever". 3. Before: 720 occurrences (~14 years). After: ~106 (2 years). task / context: extends #247929. Forward-Port-Of: odoo/odoo#272615 Forward-Port-Of: odoo/odoo#270348
Before this commit, pressing Enter or Ctrl+Enter after editing the custom favorite filter name could save the previous value instead of the latest one. This happened because `t-model.trim` synchronizes the model on the `change` event. Since the save action is triggered on `keydown`, the latest input value had not yet been propagated to the component state. This commit removes `.trim` from `t-model` and trims the description only during the save operation, ensuring the latest value is used
Original PR description
Before this commit, pressing Enter or Ctrl+Enter after editing the custom favorite filter name could save the previous value instead of the latest one. This happened because `t-model.trim` synchronizes the model on the `change` event. Since the save action is triggered on `keydown`, the latest input value had not yet been propagated to the component state. This commit removes `.trim` from `t-model` and trims the description only during the save operation, ensuring the latest value is used while preserving the existing validation against empty or whitespace-only names. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279365 Forward-Port-Of: odoo/odoo#273593
hash_sign has become very used all over the place, so more and more tokens depend on `database.secret`, increasing the impact of that secret needing one day to be rotated or being compromised. To avoid making `database.secret` a single point of failure, we would like `hash_sign` to support a custom secret supplied by caller. task-6391264 Forward-Port-Of: odoo/odoo#278256 Forward-Port-Of: odoo/odoo#276474
Original PR description
hash_sign has become very used all over the place, so more and more tokens depend on `database.secret`, increasing the impact of that secret needing one day to be rotated or being compromised. To avoid making `database.secret` a single point of failure, we would like `hash_sign` to support a custom secret supplied by caller. task-6391264 Forward-Port-Of: odoo/odoo#278256 Forward-Port-Of: odoo/odoo#276474
Steps: - Install marketing_card & website_event_track - Create a marketing card campaign for "Event Track" - Create an event with tracks - Click on "Send Cards" in event form - Choose your campaign for the mailing - Update X cards for the mailing Actual result: - Recipients is "Event Track" - Card Campaign Mailing should target model Event Track - Mailing model is still the default one during the validation Expected result: - No error - Card are updated - User will be able to s
Original PR description
Steps: - Install marketing_card & website_event_track - Create a marketing card campaign for "Event Track" - Create an event with tracks - Click on "Send Cards" in event form - Choose your campaign for the mailing - Update X cards for the mailing Actual result: - Recipients is "Event Track" - Card Campaign Mailing should target model Event Track - Mailing model is still the default one during the validation Expected result: - No error - Card are updated - User will be able to send mailing after update
The discuss action's breadcrumb name is set asynchronously: a useEffect on the current thread's displayName calls setDisplayName after the OWL render. The tour clicked "Starred messages" then immediately clicked "View or join channels" (a sidebar category action that is always present, so there was no implicit wait). Under runbot load the starred render and its effect lagged, so the action was restored with the stale "Inbox" breadcrumb name and the ".breadcrumb-item:contains('Starred messages')"
Original PR description
The discuss action's breadcrumb name is set asynchronously: a useEffect on the current thread's displayName calls setDisplayName after the OWL render. The tour clicked "Starred messages" then immediately clicked "View or join channels" (a sidebar category action that is always present, so there was no implicit wait). Under runbot load the starred render and its effect lagged, so the action was restored with the stale "Inbox" breadcrumb name and the ".breadcrumb-item:contains('Starred messages')" step timed out.
This is a test-timing artifact: a real user always sees the starred view render before navigating away, so the breadcrumb is correct for them.
Wait for the starred thread to be displayed before opening the channels list, and assert the channels view opened via its "Public Channels" breadcrumb. Also use :text instead of :contains for the text selectors.
https://runbot.odoo.com/odoo/error/242893
Forward-Port-Of: odoo/odoo#279342
Forward-Port-Of: odoo/odoo#278909The navigator class, which adds event handlers, is instanciated on the setup of components using the useNavigation hook. However, before this commit, it was destroyed when the components were unmounted. It may happen that components are instanciated (setup is executed) but never mounted in the DOM, when the current rendering is cancelled. When this happened, the navigator cleanup wasn't executed, resulting in a small memory leak. This commit fixes the issue by using onWillDestroy instead.
Original PR description
The navigator class, which adds event handlers, is instanciated on the setup of components using the useNavigation hook. However, before this commit, it was destroyed when the components were unmounted. It may happen that components are instanciated (setup is executed) but never mounted in the DOM, when the current rendering is cancelled. When this happened, the navigator cleanup wasn't executed, resulting in a small memory leak. This commit fixes the issue by using onWillDestroy instead. 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#279322
The test "show pulse effect on fullscreen mode only when another participant's camera is on" fails from time to time on runbot: the pulse never lands on the fullscreen button. The first rtc session of a channel posts a call notification message, whose new_message notification fetches channels_as_member. That response carries the rtc sessions with their server values, so when it lands after the mock remote turned the camera on, is_camera_on goes back to false. videoCountNotSelf drops to 0 and
Original PR description
The test "show pulse effect on fullscreen mode only when another participant's camera is on" fails from time to time on runbot: the pulse never lands on the fullscreen button. The first rtc session of a channel posts a call notification message, whose new_message notification fetches channels_as_member. That response carries the rtc sessions with their server values, so when it lands after the mock remote turned the camera on, is_camera_on goes back to false. videoCountNotSelf drops to 0 and its onUpdate sets promoteFullscreen to INACTIVE for good, as only a change of the count sets it back to ACTIVE. A real participant also stores is_camera_on on the server, so a fetch never brings outdated values back. Make the mock remote do the same. https://runbot.odoo.com/odoo/error/242050 Forward-Port-Of: odoo/odoo#279178
In the Italian localization, a bill should not be reset to draft once it has been sent to SDI. The exception is when the document was rejected or imported (0440cbab7a9cc183c7836fe58196799afdc00513). Steps to reproduce: - Create a vendor bill with l10n_it_edi enabled. - Send it to SDI. - The "Reset to Draft" button is still visible. opw-6350928 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273616
Original PR description
In the Italian localization, a bill should not be reset to draft once it has been sent to SDI. The exception is when the document was rejected or imported (0440cbab7a9cc183c7836fe58196799afdc00513). Steps to reproduce: - Create a vendor bill with l10n_it_edi enabled. - Send it to SDI. - The "Reset to Draft" button is still visible. opw-6350928 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273616
Clicking a Unit Cost in the stock report opens the Unit Cost History of that product. The action filters on `active_id`, which the cost cell fills with the id of the row that was clicked. That value was overwritten: the cell context was merged first and the context of the running action last, so the latter won. When the list comes from "Inventory at Date", that context carries the id of the `stock.quantity.history` record the wizard just created, which is not a product id at all. The history
Original PR description
Clicking a Unit Cost in the stock report opens the Unit Cost History of that product. The action filters on `active_id`, which the cost cell fills with the id of the row that was clicked. That value was overwritten: the cell context was merged first and the context of the running action last, so the latter won. When the list comes from "Inventory at Date", that context carries the id of the `stock.quantity.history` record the wizard just created, which is not a product id at all. The history then opens on whichever product happens to carry that id, and stays empty when none does. Steps to reproduce: - Inventory > Reporting > Stock, click a Unit Cost -> the history of that product opens, as expected - go back, click "Inventory at Date" and confirm - click that same Unit Cost -> another product's history opens, or an empty list opw-6391778 Forward-Port-Of: odoo/odoo#279116
**Issue:** `test_mail_template_dynamic_placeholder_tour` tour is failing sometimes with the following error: `Tour mail_template_dynamic_field_tour → Step Click on contact (trigger: div[name="model_id"] .ui-autocomplete). TypeError: Cannot read properties of undefined (reading 'click')` **Cause:** It happens that the element is not loaded yet after the delay and clicking on an undefined element triggers the error. **Solution:** Make sure to only click on the element when it's ready.
Original PR description
**Issue:** `test_mail_template_dynamic_placeholder_tour` tour is failing sometimes with the following error: `Tour mail_template_dynamic_field_tour → Step Click on contact (trigger: div[name="model_id"] .ui-autocomplete). TypeError: Cannot read properties of undefined (reading 'click')` **Cause:** It happens that the element is not loaded yet after the delay and clicking on an undefined element triggers the error. **Solution:** Make sure to only click on the element when it's ready. runbot-223306 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278983 Forward-Port-Of: odoo/odoo#277954
### Steps to reproduce: - Create 2 companies: c1, c2 - Create 2 storable products: P, Comp - In c1 update the available qty of P to 10 units and its cost to 50 - In c2 create a kit bom for P: 1 x Comp - With c1 > Accounting > Review > inventory > Inventory Valuation #### > The total value of Super product is 0 instead of 500 ### Cause of the issue: The total value of the product will be set to 0 since the `qty_available` of the product is incorrectly computed to be 0: https://gith
Original PR description
### Steps to reproduce: - Create 2 companies: c1, c2 - Create 2 storable products: P, Comp - In c1 update the available qty of P to 10 units and its cost to 50 - In c2 create a kit bom for P: 1 x…
### Steps to reproduce: - Create 2 companies: c1, c2 - Create 2 storable products: P, Comp - In c1 update the available qty of P to 10 units and its cost to 50 - In c2 create a kit bom for P: 1 x Comp - With c1 > Accounting > Review > inventory > Inventory Valuation #### > The total value of Super product is 0 instead of 500 ### Cause of the issue: The total value of the product will be set to 0 since the `qty_available` of the product is incorrectly computed to be 0: https://github.com/odoo/odoo/blob/cb7b3de6cea07464bcadd1325f52533d34ce09bc/addons/stock_account/models/product.py#L240-L243 This happens because the `_find_bom` used in the override of the `_compute_quantities_dict` in mrp does not consider take the contextual company into account: https://github.com/odoo/odoo/blob/cb7b3de6cea07464bcadd1325f52533d34ce09bc/addons/mrp/models/product.py#L271-L289 and hence considers incorrectly that the product is a kit. ### Note: We make the same company dependency as in the `is_kits` computation: https://github.com/odoo/odoo/blob/cb7b3de6cea07464bcadd1325f52533d34ce09bc/addons/mrp/models/product.py#L41-L47 opw-6361690 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278759 Forward-Port-Of: odoo/odoo#276306
Documentation and clarification updates
Description of the issue/feature this PR addresses: Add the Odoo Corporate Contributor License Agreement for bobco GmbH and list the employees authorized to contribute on the company's behalf. Current behavior before PR: bobco GmbH does not yet have a corporate CLA in the Odoo repository. Desired behavior after PR is merged: The corporate CLA covers the listed bobco GmbH contributors. Approval and signature status: @philipbr explicitly approved the declaration as an authorized representat
Original PR description
Description of the issue/feature this PR addresses: Add the Odoo Corporate Contributor License Agreement for bobco GmbH and list the employees authorized to contribute on the company's behalf. Current behavior before PR: bobco GmbH does not yet have a corporate CLA in the Odoo repository. Desired behavior after PR is merged: The corporate CLA covers the listed bobco GmbH contributors. Approval and signature status: @philipbr explicitly approved the declaration as an authorized representative of bobco GmbH. The signatory line has been finalized as: `Philip Braun philip@braun.tf https://github.com/philipbr` --- The corporate CLA has been signed by Philip Braun, and the PR guidelines at www.odoo.com/submit-pr have been read. Forward-Port-Of: odoo/odoo#279348
Miscellaneous changes
Optimize search_paid_order_ids to reduce ORM overhead and resolve a database bottleneck during POS synchronization. - Move currency validation from a Python post-filter into the SQL domain via config_id.currency_id. - Split the costly OR query on pos.order.line into two targeted index scans combined via UNION, dropping execution time from ~627ms to ~16ms (~40x speedup) and reducing shared read blocks from 650k+ to zero. - Align totalCount with the exact same domain and simplify state exclus
Original PR description
Optimize search_paid_order_ids to reduce ORM overhead and resolve a database bottleneck during POS synchronization. - Move currency validation from a Python post-filter into the SQL domain via config_id.currency_id. - Split the costly OR query on pos.order.line into two targeted index scans combined via UNION, dropping execution time from ~627ms to ~16ms (~40x speedup) and reducing shared read blocks from 650k+ to zero. - Align totalCount with the exact same domain and simplify state exclusions from multiple != operators to a single not in. Explain Before: https://explain.dalibo.com/plan/84095dcgfdc158a2 Explain After: https://explain.dalibo.com/plan/ag2abcdf4ge5d5e5 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278739
The government has held off the `shipToGSTIN` changes until further notice. https://services.gst.gov.in/services/advisoryandreleases/read/668 Hence, this PR reverts those changes. task-6431622 ref - https://github.com/odoo/odoo/pull/266388 Forward-Port-Of: odoo/odoo#279421
Original PR description
The government has held off the `shipToGSTIN` changes until further notice. https://services.gst.gov.in/services/advisoryandreleases/read/668 Hence, this PR reverts those changes. task-6431622 ref - https://github.com/odoo/odoo/pull/266388 Forward-Port-Of: odoo/odoo#279421
21 changes
Resolved issues and error corrections
Before this commit, pressing Enter or Ctrl+Enter after editing the custom favorite filter name could save the previous value instead of the latest one. This happened because `t-model.trim` synchronizes the model on the `change` event. Since the save action is triggered on `keydown`, the latest input value had not yet been propagated to the component state. This commit removes `.trim` from `t-model` and trims the description only during the save operation, ensuring the latest value is used
Original PR description
Before this commit, pressing Enter or Ctrl+Enter after editing the custom favorite filter name could save the previous value instead of the latest one. This happened because `t-model.trim` synchronizes the model on the `change` event. Since the save action is triggered on `keydown`, the latest input value had not yet been propagated to the component state. This commit removes `.trim` from `t-model` and trims the description only during the save operation, ensuring the latest value is used while preserving the existing validation against empty or whitespace-only names. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279365 Forward-Port-Of: odoo/odoo#273593
[FIX] stock: fix user permission to edit lots Issue: An user with the Role/User that is Inventory/Administrator is unable to edit the custom Lot/Serial Steps to reproduce: 1. Take a user with Role/User 2. Assign them Inventory/Administrator 3. Log in as this user and create a product tracked by lots 4. Go to the Inventory tab and try editing the field Custom Lot/Serial Cause: Only Role/Administrator can create Ir.Sequence, therefore even if a Role/User is Inventory/Administrator tri
Original PR description
[FIX] stock: fix user permission to edit lots Issue: An user with the Role/User that is Inventory/Administrator is unable to edit the custom Lot/Serial Steps to reproduce: 1. Take a user with Role/User 2. Assign them Inventory/Administrator 3. Log in as this user and create a product tracked by lots 4. Go to the Inventory tab and try editing the field Custom Lot/Serial Cause: Only Role/Administrator can create Ir.Sequence, therefore even if a Role/User is Inventory/Administrator tries to create a new Ir.Sequence (ex: editing a custom Lot/Serial) it will still throw him an error as he is not Role/Administrator Fix: To avoid the permissions issue at the time of creation we use sudo to bypass the Role/User lack of permissions. opw-6269415 Forward-Port-Of: odoo/odoo#278453 Forward-Port-Of: odoo/odoo#268799
The AutoComplete component wraps a text input that already renders its own suggestion dropdown, so the browser's native suggestions must stay out of the way. In 12/2024 in this commit [1] the input's autocomplete was switched from `off` to `new-password` on the premise that `off` is not respected by browsers. In 02/2025, in this commit [2] then made it the component default so many2x pickers stay clean. Chrome runs two independent suggestion mechanisms, and each attribute silences only
Original PR description
The AutoComplete component wraps a text input that already renders its own suggestion dropdown, so the browser's native suggestions must stay out of the way. In 12/2024 in this commit [1] the input's…
The AutoComplete component wraps a text input that already renders its own suggestion dropdown, so the browser's native suggestions must stay out of the way. In 12/2024 in this commit [1] the input's autocomplete was switched from `off` to `new-password` on the premise that `off` is not respected by browsers. In 02/2025, in this commit [2] then made it the component default so many2x pickers stay clean. Chrome runs two independent suggestion mechanisms, and each attribute silences only one of them: - `off` is ignored when the input has a name and Chrome holds autofill (address) data for it. - `new-password` is ignored when Chrome offers "frequently used values", i.e. the form-history dropdown. [3] So `new-password` does not always work. It only stays hidden while the field is ineligible for those suggestions. A field becomes eligible as soon as it gains an `id` and an associated `<label>`. On `saas-19.3` this is provable on commit [4] where adding a prefix icon gave the link popover URL input an `id` + `<label for>`, and the native dropdown resurfaced over the custom URL/page suggestions. This branch targets `saas-18.4`, where the regression is NOT reproducible because that URL input has no `id`/`label` yet. The fix is applied here anyway to avoid the gap that any later `label`/`id` addition re-exposes (as commit [4] proved), and the fix can be forward ported to `saas-19.3`. The website editor's URL field implements autocomplete without the `AutoComplete` component, so the default does not reach it. so `autocomplete="off"` is set directly on that input. [1]: https://github.com/odoo/odoo/commit/9c0f5612 [2]: https://github.com/odoo/odoo/commit/2980694b (opw-4551051) [3]: https://issues.chromium.org/issues/41163264#comment30 [4]: https://github.com/odoo/odoo/commit/2b4d04d1 (task-6034288) task-6370552 Forward-Port-Of: odoo/odoo#279203 Forward-Port-Of: odoo/odoo#277501
Stripe recommends connecting to a reader returned by the most recent discovery call. However, the POS Stripe interface discovered readers as soon as the Stripe Terminal object was created, during POS loading. This means a POS reload performed long before the first payment could populate `pos.discoveredReaders` with stale reader objects. If the first Stripe Terminal payment happens much later, the SDK may try to connect using outdated reader/credential state and fail with an expired Connection
Original PR description
Stripe recommends connecting to a reader returned by the most recent discovery call. However, the POS Stripe interface discovered readers as soon as the Stripe Terminal object was created, during POS loading. This means a POS reload performed long before the first payment could populate `pos.discoveredReaders` with stale reader objects. If the first Stripe Terminal payment happens much later, the SDK may try to connect using outdated reader/credential state and fail with an expired ConnectionToken. Move reader discovery to `connectReader()` so Odoo connects using fresh discovery results, and stop discovering readers eagerly when creating the Stripe Terminal instance. opw-6311626 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277765 Forward-Port-Of: odoo/odoo#276875
Steps to reproduce --- 1. Confirm a purchase order and receive it a few days later. 2. Open Purchase, Reporting, Purchase and add the "Effective Days To Arrival" measure. Observed: the value is counted from the line's scheduled date instead of the order date, and can even be negative when the scheduled date precedes the confirmation date. Issue --- The metric is meant to be the effective lead time, the number of days between the order confirmation and the actual receipt, falling back
Original PR description
Steps to reproduce --- 1. Confirm a purchase order and receive it a few days later. 2. Open Purchase, Reporting, Purchase and add the "Effective Days To Arrival" measure. Observed: the value is…
Steps to reproduce --- 1. Confirm a purchase order and receive it a few days later. 2. Open Purchase, Reporting, Purchase and add the "Effective Days To Arrival" measure. Observed: the value is counted from the line's scheduled date instead of the order date, and can even be negative when the scheduled date precedes the confirmation date. Issue --- The metric is meant to be the effective lead time, the number of days between the order confirmation and the actual receipt, falling back to the planned "days to receive" when nothing has been received yet according to [task](https://www.odoo.com/odoo/project/809/tasks/3691573). The query instead computes age(date_planned, COALESCE(date_done, date_order)), so once a receipt exists it returns date_planned - date_done (the gap between the scheduled date and the receipt) rather than date_done - date_order. https://github.com/odoo/odoo/blob/c06be48ce7277a667719fd756e0a1f63e91cda27/addons/purchase_stock/report/purchase_report.py#L20-L28 opw-6226523 Forward-Port-Of: odoo/odoo#279267 Forward-Port-Of: odoo/odoo#268843
Taxes with SAF-T code 21 and 22 are not correct and needed modification where they should be set to 0% because: - The foreign supplier invoices without Norwegian VAT, so the invoice total shouldn't increase - You must still self-assess 25% VAT and report it - The 25% is booked as both output and input VAT simultaneously → net cash effect = 0 - Only the basis amount is reported in the VAT return (import boxes) task-6254727 Forward-Port-Of: odoo/odoo#278896 Forward-Port-Of: odoo/odoo#26751
Original PR description
Taxes with SAF-T code 21 and 22 are not correct and needed modification where they should be set to 0% because: - The foreign supplier invoices without Norwegian VAT, so the invoice total shouldn't increase - You must still self-assess 25% VAT and report it - The 25% is booked as both output and input VAT simultaneously → net cash effect = 0 - Only the basis amount is reported in the VAT return (import boxes) task-6254727 Forward-Port-Of: odoo/odoo#278896 Forward-Port-Of: odoo/odoo#267510
The mail.message/delete bus handler accessed selfMember?.seen_message_id.id with optional chaining only on selfMember, not on seen_message_id. When a member has never seen any message in a channel (seen_message_id is False), accessing .id threw 'TypeError: can't access property id, selfMember.seen_message_id is undefined', breaking message deletion for that user (e.g. deleting a message in a channel the user never opened. Add optional chaining on seen_message_id so the unread counter is simpl
Original PR description
The mail.message/delete bus handler accessed selfMember?.seen_message_id.id with optional chaining only on selfMember, not on seen_message_id. When a member has never seen any message in a channel (seen_message_id is False), accessing .id threw 'TypeError: can't access property id, selfMember.seen_message_id is undefined', breaking message deletion for that user (e.g. deleting a message in a channel the user never opened. Add optional chaining on seen_message_id so the unread counter is simply not decremented when no message has been seen yet. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279279 Forward-Port-Of: odoo/odoo#277417
Test `load dashboard that doesn't exist` sometimes fails because the test doesn't wait for the rpc to complete before checking the error message. This commit adds a wait for the next animation frame to ensure the rpc has completed before checking the error message. Runbot-940389 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/su
Original PR description
Test `load dashboard that doesn't exist` sometimes fails because the test doesn't wait for the rpc to complete before checking the error message. This commit adds a wait for the next animation frame to ensure the rpc has completed before checking the error message. Runbot-940389 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#279418
The navigator class, which adds event handlers, is instanciated on the setup of components using the useNavigation hook. However, before this commit, it was destroyed when the components were unmounted. It may happen that components are instanciated (setup is executed) but never mounted in the DOM, when the current rendering is cancelled. When this happened, the navigator cleanup wasn't executed, resulting in a small memory leak. This commit fixes the issue by using onWillDestroy instead.
Original PR description
The navigator class, which adds event handlers, is instanciated on the setup of components using the useNavigation hook. However, before this commit, it was destroyed when the components were unmounted. It may happen that components are instanciated (setup is executed) but never mounted in the DOM, when the current rendering is cancelled. When this happened, the navigator cleanup wasn't executed, resulting in a small memory leak. This commit fixes the issue by using onWillDestroy instead. 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#279322
Problem: When adding a caption to an image, typing text, then undoing and redoing does not restore the caption content. Cause: The caption used a native `<input>` element whose content is managed by the browser, not the editor's history stack. While redo could restore the input element itself, its content was lost since the editor never tracked it. Solution: Replace the `<input>` with a `contenteditable` `<span>` so the editor manages its content as part of the DOM history, enabling ful
Original PR description
Problem: When adding a caption to an image, typing text, then undoing and redoing does not restore the caption content. Cause: The caption used a native `<input>` element whose content is managed by the browser, not the editor's history stack. While redo could restore the input element itself, its content was lost since the editor never tracked it. Solution: Replace the `<input>` with a `contenteditable` `<span>` so the editor manages its content as part of the DOM history, enabling full undo/redo. Changes: - Use a contenteditable `<span>` instead of `<input>` for caption editing - Prevent pasting HTML inside the span (plain text only) - Limit caption content to 100 characters - Disable power box, toolbar, and paragraph insertion inside the span task-6219868 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278901 Forward-Port-Of: odoo/odoo#267211
Issue: --- Adding a rating with a message on website is causing TB as the portal user doesn't have the access to send rating message. opw-6316142 Forward-Port-Of: odoo/odoo#279171 Forward-Port-Of: odoo/odoo#271833
Original PR description
Issue: --- Adding a rating with a message on website is causing TB as the portal user doesn't have the access to send rating message. opw-6316142 Forward-Port-Of: odoo/odoo#279171 Forward-Port-Of: odoo/odoo#271833
Before this commit, the composer suggestion list could re-open right after the user closed it with Escape, and the next press of Escape would then close the list again instead of being handled by the composer (e.g. discarding a reply). This happened because NavigableList was re-opened on every patch: the useEffect opening the list had `[this.props]` as dependency, and props are a new object on every render. Any unrelated re-render of the composer (e.g. triggered by a late store update) would
Original PR description
Before this commit, the composer suggestion list could re-open right after the user closed it with Escape, and the next press of Escape would then close the list again instead of being handled by the composer (e.g. discarding a reply). This happened because NavigableList was re-opened on every patch: the useEffect opening the list had `[this.props]` as dependency, and props are a new object on every render. Any unrelated re-render of the composer (e.g. triggered by a late store update) would therefore re-open the list, which would then steal the next Escape from the composer. Fix by narrowing the dependency to the content of the options, so the list only opens on mount and when a new set of options arrives. https://runbot.odoo.com/odoo/error/944571 Forward-Port-Of: odoo/odoo#279275 Forward-Port-Of: odoo/odoo#278929
In the Italian localization, a bill should not be reset to draft once it has been sent to SDI. The exception is when the document was rejected or imported (0440cbab7a9cc183c7836fe58196799afdc00513). Steps to reproduce: - Create a vendor bill with l10n_it_edi enabled. - Send it to SDI. - The "Reset to Draft" button is still visible. opw-6350928 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273616
Original PR description
In the Italian localization, a bill should not be reset to draft once it has been sent to SDI. The exception is when the document was rejected or imported (0440cbab7a9cc183c7836fe58196799afdc00513). Steps to reproduce: - Create a vendor bill with l10n_it_edi enabled. - Send it to SDI. - The "Reset to Draft" button is still visible. opw-6350928 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273616
Clicking a Unit Cost in the stock report opens the Unit Cost History of that product. The action filters on `active_id`, which the cost cell fills with the id of the row that was clicked. That value was overwritten: the cell context was merged first and the context of the running action last, so the latter won. When the list comes from "Inventory at Date", that context carries the id of the `stock.quantity.history` record the wizard just created, which is not a product id at all. The history
Original PR description
Clicking a Unit Cost in the stock report opens the Unit Cost History of that product. The action filters on `active_id`, which the cost cell fills with the id of the row that was clicked. That value was overwritten: the cell context was merged first and the context of the running action last, so the latter won. When the list comes from "Inventory at Date", that context carries the id of the `stock.quantity.history` record the wizard just created, which is not a product id at all. The history then opens on whichever product happens to carry that id, and stays empty when none does. Steps to reproduce: - Inventory > Reporting > Stock, click a Unit Cost -> the history of that product opens, as expected - go back, click "Inventory at Date" and confirm - click that same Unit Cost -> another product's history opens, or an empty list opw-6391778 Forward-Port-Of: odoo/odoo#279116
With the Shared Customer Account setting enabled, a user created in c1 cannot access the shop in the website of c2 Steps to reproduce: 1. Install eCommerce and Contacts 2. Go to Settings > Users & Companies > Companies and create two companies c1 and c2 3. Go to Website > Configuration > Websites and create two websites w1 with company c1 and w2 with company c2 4. Change the order of the websites so that w1 is at the top 5. Go to Website > eCommerce > Pricelists and create a pricelist pl
Original PR description
With the Shared Customer Account setting enabled, a user created in c1 cannot access the shop in the website of c2 Steps to reproduce: 1. Install eCommerce and Contacts 2. Go to Settings > Users &…
With the Shared Customer Account setting enabled, a user created in c1 cannot access the shop in the website of c2 Steps to reproduce: 1. Install eCommerce and Contacts 2. Go to Settings > Users & Companies > Companies and create two companies c1 and c2 3. Go to Website > Configuration > Websites and create two websites w1 with company c1 and w2 with company c2 4. Change the order of the websites so that w1 is at the top 5. Go to Website > eCommerce > Pricelists and create a pricelist pl1 in c1 assigned to w1 and pl2 in c2 assigned to w2 6. In an incognito tab, go to w1 and create a new account 7. As admin, go to Website > Configuration > Websites and change the order of the websites so that w2 is at the top 8. In an incognito tab, connect with the previously created account and go to the shop 9. An error is thrown (This error only happens when geoip works, i.e. when `_get_geoip_country_code` returns something) Issue: When geoip returns a country code, we search through all the pricelists available for that country code but some of them can be restricted to a company which raises an access error. We need to be able to access them in order to filter the ones that are not available on the current website Solution: Access all pricelists with sudo, they will be filtered out with `_is_available_on_website` opw-3574089 Forward-Port-Of: odoo/odoo#268863
**Issue:** `test_mail_template_dynamic_placeholder_tour` tour is failing sometimes with the following error: `Tour mail_template_dynamic_field_tour → Step Click on contact (trigger: div[name="model_id"] .ui-autocomplete). TypeError: Cannot read properties of undefined (reading 'click')` **Cause:** It happens that the element is not loaded yet after the delay and clicking on an undefined element triggers the error. **Solution:** Make sure to only click on the element when it's ready.
Original PR description
**Issue:** `test_mail_template_dynamic_placeholder_tour` tour is failing sometimes with the following error: `Tour mail_template_dynamic_field_tour → Step Click on contact (trigger: div[name="model_id"] .ui-autocomplete). TypeError: Cannot read properties of undefined (reading 'click')` **Cause:** It happens that the element is not loaded yet after the delay and clicking on an undefined element triggers the error. **Solution:** Make sure to only click on the element when it's ready. runbot-223306 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278983 Forward-Port-Of: odoo/odoo#277954
When an image is start-aligned, if a list is defined after it, its bullets/numbers/checkboxes are rendered on top of the image. This commit makes the bullets rendered after the image. Steps to reproduce: - Edit a website page - Drop a text page - Insert an image with `/image` - Align image to the left - Insert a bullet list or a numbered list or a checkbox list with some indented entries => Some bullets were rendered on top of the image Additionally, the start-align is neutral
Original PR description
When an image is start-aligned, if a list is defined after it, its bullets/numbers/checkboxes are rendered on top of the image. This commit makes the bullets rendered after the image. Steps to reproduce: - Edit a website page - Drop a text page - Insert an image with `/image` - Align image to the left - Insert a bullet list or a numbered list or a checkbox list with some indented entries => Some bullets were rendered on top of the image Additionally, the start-align is neutralized inside list lines because other approaches do not provide a satisfactory layout - and break further situations. task-6116437 Forward-Port-Of: odoo/odoo#260325
Routes inherited from product category are not available when on replenish. Steps to reproduce: ------------------- * Create a new route and allow it on product category * Create a product category and add the route * Add the category to a product * use the repenish button -> the category route is not available on the replenishment Observation: ------------- When opening replenishment, it will open the view_product_replenish, in that view, it will use allowed_route_ids to allow us
Original PR description
Routes inherited from product category are not available when on replenish. Steps to reproduce: ------------------- * Create a new route and allow it on product category * Create a product category…
Routes inherited from product category are not available when on replenish. Steps to reproduce: ------------------- * Create a new route and allow it on product category * Create a product category and add the route * Add the category to a product * use the repenish button -> the category route is not available on the replenishment Observation: ------------- When opening replenishment, it will open the view_product_replenish, in that view, it will use allowed_route_ids to allow us to choose a route for this replenishment: https://github.com/odoo/odoo/blob/2f25b2a70eca5b4f3c2e1d6c7003b1760afc0ba0/addons/stock/wizard/product_replenish_views.xml#L37 allowed_route_ids is compute in the mixin with the following domain: https://github.com/odoo/odoo/blob/2f25b2a70eca5b4f3c2e1d6c7003b1760afc0ba0/addons/stock/models/stock_replenish_mixin.py#L18-L21 https://github.com/odoo/odoo/blob/2f25b2a70eca5b4f3c2e1d6c7003b1760afc0ba0/addons/stock/models/stock_replenish_mixin.py#L25-L31 this only take into account route from the product and not the ones from the product category. https://github.com/odoo/odoo/blob/deeecf7cd02e7383b591835b0c6495e3ddead0ff/addons/stock/models/stock_location.py#L511 opw-6297308 Forward-Port-Of: odoo/odoo#271535
Before this commit, the pointerup event when doing a drag'n'drop in kanban view was containing the kanban card placeholder. Now, this placeholder isn't considered anymore to prevent unwanted target in the event. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278324
Original PR description
Before this commit, the pointerup event when doing a drag'n'drop in kanban view was containing the kanban card placeholder. Now, this placeholder isn't considered anymore to prevent unwanted target in the event. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278324
Documentation and clarification updates
Description of the issue/feature this PR addresses: Add the Odoo Corporate Contributor License Agreement for bobco GmbH and list the employees authorized to contribute on the company's behalf. Current behavior before PR: bobco GmbH does not yet have a corporate CLA in the Odoo repository. Desired behavior after PR is merged: The corporate CLA covers the listed bobco GmbH contributors. Approval and signature status: @philipbr explicitly approved the declaration as an authorized representat
Original PR description
Description of the issue/feature this PR addresses: Add the Odoo Corporate Contributor License Agreement for bobco GmbH and list the employees authorized to contribute on the company's behalf. Current behavior before PR: bobco GmbH does not yet have a corporate CLA in the Odoo repository. Desired behavior after PR is merged: The corporate CLA covers the listed bobco GmbH contributors. Approval and signature status: @philipbr explicitly approved the declaration as an authorized representative of bobco GmbH. The signatory line has been finalized as: `Philip Braun philip@braun.tf https://github.com/philipbr` --- The corporate CLA has been signed by Philip Braun, and the PR guidelines at www.odoo.com/submit-pr have been read. Forward-Port-Of: odoo/odoo#279348
Miscellaneous changes
The government has held off the `shipToGSTIN` changes until further notice. https://services.gst.gov.in/services/advisoryandreleases/read/668 Hence, this PR reverts those changes. task-6431622 ref - https://github.com/odoo/odoo/pull/266388 Forward-Port-Of: odoo/odoo#279421
Original PR description
The government has held off the `shipToGSTIN` changes until further notice. https://services.gst.gov.in/services/advisoryandreleases/read/668 Hence, this PR reverts those changes. task-6431622 ref - https://github.com/odoo/odoo/pull/266388 Forward-Port-Of: odoo/odoo#279421
20 changes
Resolved issues and error corrections
When a PoS runs in a currency other than the company currency, product prices are loaded already converted to the PoS currency (`list_price`, `lst_price`, `standard_price` all go through `_convert_pos_data_currency`). The prices carried by combos were not: `product.combo.base_price` is computed in the combo currency (the company currency) and `product.combo.item.extra_price` is stored in the product currency, but neither was converted when loaded in the PoS. As a result, a product priced at 2
Original PR description
When a PoS runs in a currency other than the company currency, product prices are loaded already converted to the PoS currency (`list_price`, `lst_price`, `standard_price` all go through…
When a PoS runs in a currency other than the company currency, product prices are loaded already converted to the PoS currency (`list_price`, `lst_price`, `standard_price` all go through `_convert_pos_data_currency`). The prices carried by combos were not: `product.combo.base_price` is computed in the combo currency (the company currency) and `product.combo.item.extra_price` is stored in the product currency, but neither was converted when loaded in the PoS. As a result, a product priced at 2 USD (= 80 ZIG) was correctly shown as 80 ZIG on its own, yet appeared as 2 ZIG once it was part of a combo, since the raw amount was displayed as-is in the PoS currency. Convert `base_price` and `extra_price` from each record's own `currency_id` to the PoS currency at load time, mirroring what is already done for product prices. Steps to reproduce: - Set a product to 2 USD and a PoS to a ZIG pricelist (rate 40). - Open the PoS: the standalone product shows 80 ZIG. - Add the same product as a combo item: it shows 2 ZIG instead of 80 ZIG. opw-6410243 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278330
When a product with no attributes is sold, the description_picking field of the stock.move is empty. Steps to reproduce: ------------------- * Create a product with no attributes * Create a sale order with this product * Confirm the sale order > Observation: The description_picking field of the stock.move is empty The issue was originally reported because the e-Waybill in India had an empty description for the product. Why the fix: ------------ When trying to avoid duplicating th
Original PR description
When a product with no attributes is sold, the description_picking field of the stock.move is empty. Steps to reproduce: ------------------- * Create a product with no attributes * Create a sale order with this product * Confirm the sale order > Observation: The description_picking field of the stock.move is empty The issue was originally reported because the e-Waybill in India had an empty description for the product. Why the fix: ------------ When trying to avoid duplicating the product name, we should first check that it would not result in an empty description picking. opw-6318785 Forward-Port-Of: odoo/odoo#275248
Before this commit, pressing Enter or Ctrl+Enter after editing the custom favorite filter name could save the previous value instead of the latest one. This happened because `t-model.trim` synchronizes the model on the `change` event. Since the save action is triggered on `keydown`, the latest input value had not yet been propagated to the component state. This commit removes `.trim` from `t-model` and trims the description only during the save operation, ensuring the latest value is used
Original PR description
Before this commit, pressing Enter or Ctrl+Enter after editing the custom favorite filter name could save the previous value instead of the latest one. This happened because `t-model.trim` synchronizes the model on the `change` event. Since the save action is triggered on `keydown`, the latest input value had not yet been propagated to the component state. This commit removes `.trim` from `t-model` and trims the description only during the save operation, ensuring the latest value is used while preserving the existing validation against empty or whitespace-only names. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279365 Forward-Port-Of: odoo/odoo#273593
Stripe recommends connecting to a reader returned by the most recent discovery call. However, the POS Stripe interface discovered readers as soon as the Stripe Terminal object was created, during POS loading. This means a POS reload performed long before the first payment could populate `pos.discoveredReaders` with stale reader objects. If the first Stripe Terminal payment happens much later, the SDK may try to connect using outdated reader/credential state and fail with an expired Connection
Original PR description
Stripe recommends connecting to a reader returned by the most recent discovery call. However, the POS Stripe interface discovered readers as soon as the Stripe Terminal object was created, during POS loading. This means a POS reload performed long before the first payment could populate `pos.discoveredReaders` with stale reader objects. If the first Stripe Terminal payment happens much later, the SDK may try to connect using outdated reader/credential state and fail with an expired ConnectionToken. Move reader discovery to `connectReader()` so Odoo connects using fresh discovery results, and stop discovering readers eagerly when creating the Stripe Terminal instance. opw-6311626 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277765 Forward-Port-Of: odoo/odoo#276875
### Steps to reproduce: - In the settings enable: Multi-Steps Routes - Inventory > Configuration > Warehouse Management > Warehouses - Set your warehouse deliveries in two steps - Inventory > Operations > Tranfers > Internal > New - Set the operation type as Pick, set a partner and add Partner: Bob - In the sales & Purchase tab of the partner form set a customer location to be a child of the Customers location: Customers/Bob'Stock - Confirm and validate the Pick for 1 unit of a product
Original PR description
### Steps to reproduce: - In the settings enable: Multi-Steps Routes - Inventory > Configuration > Warehouse Management > Warehouses - Set your warehouse deliveries in two steps - Inventory >…
### Steps to reproduce: - In the settings enable: Multi-Steps Routes - Inventory > Configuration > Warehouse Management > Warehouses - Set your warehouse deliveries in two steps - Inventory > Operations > Tranfers > Internal > New - Set the operation type as Pick, set a partner and add Partner: Bob - In the sales & Purchase tab of the partner form set a customer location to be a child of the Customers location: Customers/Bob'Stock - Confirm and validate the Pick for 1 unit of a product P #### > A ship picking is created but the destination of the related move is still set to the default customer location. ### Note: If the flow is performed by a sale order, the `property_stock_customer` location will appropriately be used as `location_final_id`: https://github.com/odoo/odoo/blob/7609b5805c3704034b4d7813e2f356381ed18771/addons/sale_stock/models/sale_order_line.py#L297 https://github.com/odoo/odoo/blob/7609b5805c3704034b4d7813e2f356381ed18771/addons/sale_stock/models/sale_order_line.py#L306-L309 https://github.com/odoo/odoo/blob/720598d0315dbb91628441078febfd43ffefb431/addons/stock/models/stock_rule.py#L263-L264 So that the bug does not occur in that case. By contrast if the pick move is created manually, we do not set its `location_final_id` and hence do not propagate the info. Even though it looks expected to be set set as location_dest_id of the ship move sas suggested by the `stock.picking.location_dest_id` compute method : https://github.com/odoo/odoo/blob/fe3aea07a1964cd24f4c8ebf2bc93e483eca6b0b/addons/stock/models/stock_picking.py#L990-L1002 opw-6402483 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278838
Taxes with SAF-T code 21 and 22 are not correct and needed modification where they should be set to 0% because: - The foreign supplier invoices without Norwegian VAT, so the invoice total shouldn't increase - You must still self-assess 25% VAT and report it - The 25% is booked as both output and input VAT simultaneously → net cash effect = 0 - Only the basis amount is reported in the VAT return (import boxes) task-6254727 Forward-Port-Of: odoo/odoo#278896 Forward-Port-Of: odoo/odoo#26751
Original PR description
Taxes with SAF-T code 21 and 22 are not correct and needed modification where they should be set to 0% because: - The foreign supplier invoices without Norwegian VAT, so the invoice total shouldn't increase - You must still self-assess 25% VAT and report it - The 25% is booked as both output and input VAT simultaneously → net cash effect = 0 - Only the basis amount is reported in the VAT return (import boxes) task-6254727 Forward-Port-Of: odoo/odoo#278896 Forward-Port-Of: odoo/odoo#267510
Once the cron is called to update current_version_id, the new employee calendar is applied to the previous version as well, due to the inverse on resource.resource def _inverse_calendar_id(self): for resource in self: if resource.calendar_id != resource.employee_id.resource_calendar_id: resource.employee_id.resource_calendar_id = resource.calendar_id All that because the introduced piece of code was called before super if 'current_versi
Original PR description
Once the cron is called to update current_version_id, the new employee calendar is applied to the previous version as well, due to the inverse on resource.resource
def _inverse_calendar_id(self):
for resource in self:
if resource.calendar_id != resource.employee_id.resource_calendar_id:
resource.employee_id.resource_calendar_id = resource.calendar_id
All that because the introduced piece of code was called before super
if 'current_version_id' in vals:
new_version = self.env['hr.version'].browse(vals.get('current_version_id'))
self.resource_id.calendar_id = new_version.resource_calendar_id
And this the inverse method was called on the previous version (not yet updated), not the new one.
Forward-Port-Of: odoo/odoo#279048Issue: --- Adding a rating with a message on website is causing TB as the portal user doesn't have the access to send rating message. opw-6316142 Forward-Port-Of: odoo/odoo#279171 Forward-Port-Of: odoo/odoo#271833
Original PR description
Issue: --- Adding a rating with a message on website is causing TB as the portal user doesn't have the access to send rating message. opw-6316142 Forward-Port-Of: odoo/odoo#279171 Forward-Port-Of: odoo/odoo#271833
Test `load dashboard that doesn't exist` sometimes fails because the test doesn't wait for the rpc to complete before checking the error message. This commit adds a wait for the next animation frame to ensure the rpc has completed before checking the error message. Runbot-940389 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/su
Original PR description
Test `load dashboard that doesn't exist` sometimes fails because the test doesn't wait for the rpc to complete before checking the error message. This commit adds a wait for the next animation frame to ensure the rpc has completed before checking the error message. Runbot-940389 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#279418
Allow to add the district node for the peruvian electronic invoicing. opw-6282314 Forward-Port-Of: odoo/odoo#271364
Original PR description
Allow to add the district node for the peruvian electronic invoicing. opw-6282314 Forward-Port-Of: odoo/odoo#271364
The navigator class, which adds event handlers, is instanciated on the setup of components using the useNavigation hook. However, before this commit, it was destroyed when the components were unmounted. It may happen that components are instanciated (setup is executed) but never mounted in the DOM, when the current rendering is cancelled. When this happened, the navigator cleanup wasn't executed, resulting in a small memory leak. This commit fixes the issue by using onWillDestroy instead.
Original PR description
The navigator class, which adds event handlers, is instanciated on the setup of components using the useNavigation hook. However, before this commit, it was destroyed when the components were unmounted. It may happen that components are instanciated (setup is executed) but never mounted in the DOM, when the current rendering is cancelled. When this happened, the navigator cleanup wasn't executed, resulting in a small memory leak. This commit fixes the issue by using onWillDestroy instead. 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#279322
to reproduce: ============= - Have a database with a large number of kit BoMs (e.g. ~160k phantom mrp.bom records). - Open Inventory Valuation. - The request never returns and hangs forever. problem: ======== Commit 11e9c1297439 started searching the valued products with `('qty_available', '!=', 0)`. On `product.product` this triggers the mrp override `_search_qty_available_new`, which loads every phantom BoM in the database and computes `qty_available` (via BoM explode) for each
Original PR description
to reproduce: ============= - Have a database with a large number of kit BoMs (e.g. ~160k phantom mrp.bom records). - Open Inventory Valuation. - The request never returns and hangs forever. problem:…
to reproduce:
=============
- Have a database with a large number of kit BoMs (e.g. ~160k phantom
mrp.bom records).
- Open Inventory Valuation.
- The request never returns and hangs forever.
problem:
========
Commit 11e9c1297439 started searching the valued products with
`('qty_available', '!=', 0)`. On `product.product` this triggers the mrp
override `_search_qty_available_new`, which loads every phantom BoM in the
database and computes `qty_available` (via BoM explode) for each kit. On top
of that, the override builds the kit products recordset with repeated
`kit_products |= ...` unions, which is O(n^2). With a large catalog of kits
the combination of O(n) heavy explodes and O(n^2) unions never returns.
On top of the performance issue, the new search dropped the kit exclusion
that `_get_accounts_by_product` previously applied through
`_get_valuation_product_domain` (`('is_kits', '=', False)` in mrp_account),
so phantom products - which are never valued on their own - were wrongly
pulled into the valuation.
solution:
=========
Restore the kit exclusion: search the valued products through
`_get_valuation_product_domain()` (which adds `('is_kits', '=', False)` in
mrp_account) instead of the ad-hoc `('is_storable', '=', True)` domain, so
phantom products are no longer valued.
Add a `skip_kit_qty_available` context key on `_search_qty_available_new` so
callers that intentionally exclude kits can skip the costly kit BoM expansion
and return the base (quant-based) result directly. The key is set in
mrp_account (via `_get_valuation_product_context`), alongside the domain that
already excludes kits, so the optimization and its precondition stay in the
same layer.
Also make the remaining kit path in `_search_qty_available_new` scale: build
the kit products recordset in a single pass instead of O(n^2) recordset
unions, and use a set for membership checks.
Benchmark:
==========
for `_get_report_data()` (averaged over 5 runs):
| # Input data (phantom kits) | Before PR | After PR |
| :---: | :---: | :---: |
| 1,000 | 2.558 s | 35.5 ms |
| 5,000 | 10.991 s | 41.6 ms |
| 10,000 | 20.869 s | 66.0 ms |
| 25,000 | 61.807 s | 80.7 ms |
| 50,000 | 195.382 s | 87.9 ms |
the improvement is **~99% faster**
opw-6312168
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#273982In the Italian localization, a bill should not be reset to draft once it has been sent to SDI. The exception is when the document was rejected or imported (0440cbab7a9cc183c7836fe58196799afdc00513). Steps to reproduce: - Create a vendor bill with l10n_it_edi enabled. - Send it to SDI. - The "Reset to Draft" button is still visible. opw-6350928 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273616
Original PR description
In the Italian localization, a bill should not be reset to draft once it has been sent to SDI. The exception is when the document was rejected or imported (0440cbab7a9cc183c7836fe58196799afdc00513). Steps to reproduce: - Create a vendor bill with l10n_it_edi enabled. - Send it to SDI. - The "Reset to Draft" button is still visible. opw-6350928 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273616
Issue: Hourly Time Off requests can keep the hours computed for the previous request date after the user changes the date when using custom working hours. Steps to reproduce: - Configure an employee schedule with Wednesday 07:30-16:15 and Thursday 07:30-16:30. - Create an hourly Time Off request on Wednesday (extra hours), Observe the hours are from 07:30-16:15. - Change the request date to Monday, Observe the hours will still be from 07:30-16:15 not 07:30-16:30. Cause: This was intro
Original PR description
Issue: Hourly Time Off requests can keep the hours computed for the previous request date after the user changes the date when using custom working hours. Steps to reproduce: - Configure an employee…
Issue: Hourly Time Off requests can keep the hours computed for the previous request date after the user changes the date when using custom working hours. Steps to reproduce: - Configure an employee schedule with Wednesday 07:30-16:15 and Thursday 07:30-16:30. - Create an hourly Time Off request on Wednesday (extra hours), Observe the hours are from 07:30-16:15. - Change the request date to Monday, Observe the hours will still be from 07:30-16:15 not 07:30-16:30. Cause: This was introduced by this commit https://github.com/odoo/odoo/commit/acc03a1d890d2e8bd39e1506475df4c917697111 https://github.com/odoo/odoo/blob/3592b7826ca0c7c30511705e3282dd2c39a901ac/addons/hr_holidays/models/hr_leave.py#L255-L273 preserves non-empty `request_hour_from/request_hour_to` on hourly requests, but no date onchange refreshes those values when they were calendar defaults for the previous date, so it skipped recomputing `request_hour_from/request_hour_to` whenever `request_unit_hours` was set and both hour fields already had values, treating auto filled schedule hours as manual values. Solution: Add a request date onchange to recompute hourly defaults from the new date schedule, while preserving manually selected hours when they differ from the previous calendar default. opw-6259899 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#271582
Clicking a Unit Cost in the stock report opens the Unit Cost History of that product. The action filters on `active_id`, which the cost cell fills with the id of the row that was clicked. That value was overwritten: the cell context was merged first and the context of the running action last, so the latter won. When the list comes from "Inventory at Date", that context carries the id of the `stock.quantity.history` record the wizard just created, which is not a product id at all. The history
Original PR description
Clicking a Unit Cost in the stock report opens the Unit Cost History of that product. The action filters on `active_id`, which the cost cell fills with the id of the row that was clicked. That value was overwritten: the cell context was merged first and the context of the running action last, so the latter won. When the list comes from "Inventory at Date", that context carries the id of the `stock.quantity.history` record the wizard just created, which is not a product id at all. The history then opens on whichever product happens to carry that id, and stays empty when none does. Steps to reproduce: - Inventory > Reporting > Stock, click a Unit Cost -> the history of that product opens, as expected - go back, click "Inventory at Date" and confirm - click that same Unit Cost -> another product's history opens, or an empty list opw-6391778 Forward-Port-Of: odoo/odoo#279116
With the Shared Customer Account setting enabled, a user created in c1 cannot access the shop in the website of c2 Steps to reproduce: 1. Install eCommerce and Contacts 2. Go to Settings > Users & Companies > Companies and create two companies c1 and c2 3. Go to Website > Configuration > Websites and create two websites w1 with company c1 and w2 with company c2 4. Change the order of the websites so that w1 is at the top 5. Go to Website > eCommerce > Pricelists and create a pricelist pl
Original PR description
With the Shared Customer Account setting enabled, a user created in c1 cannot access the shop in the website of c2 Steps to reproduce: 1. Install eCommerce and Contacts 2. Go to Settings > Users &…
With the Shared Customer Account setting enabled, a user created in c1 cannot access the shop in the website of c2 Steps to reproduce: 1. Install eCommerce and Contacts 2. Go to Settings > Users & Companies > Companies and create two companies c1 and c2 3. Go to Website > Configuration > Websites and create two websites w1 with company c1 and w2 with company c2 4. Change the order of the websites so that w1 is at the top 5. Go to Website > eCommerce > Pricelists and create a pricelist pl1 in c1 assigned to w1 and pl2 in c2 assigned to w2 6. In an incognito tab, go to w1 and create a new account 7. As admin, go to Website > Configuration > Websites and change the order of the websites so that w2 is at the top 8. In an incognito tab, connect with the previously created account and go to the shop 9. An error is thrown (This error only happens when geoip works, i.e. when `_get_geoip_country_code` returns something) Issue: When geoip returns a country code, we search through all the pricelists available for that country code but some of them can be restricted to a company which raises an access error. We need to be able to access them in order to filter the ones that are not available on the current website Solution: Access all pricelists with sudo, they will be filtered out with `_is_available_on_website` opw-3574089 Forward-Port-Of: odoo/odoo#268863
**Issue:** `test_mail_template_dynamic_placeholder_tour` tour is failing sometimes with the following error: `Tour mail_template_dynamic_field_tour → Step Click on contact (trigger: div[name="model_id"] .ui-autocomplete). TypeError: Cannot read properties of undefined (reading 'click')` **Cause:** It happens that the element is not loaded yet after the delay and clicking on an undefined element triggers the error. **Solution:** Make sure to only click on the element when it's ready.
Original PR description
**Issue:** `test_mail_template_dynamic_placeholder_tour` tour is failing sometimes with the following error: `Tour mail_template_dynamic_field_tour → Step Click on contact (trigger: div[name="model_id"] .ui-autocomplete). TypeError: Cannot read properties of undefined (reading 'click')` **Cause:** It happens that the element is not loaded yet after the delay and clicking on an undefined element triggers the error. **Solution:** Make sure to only click on the element when it's ready. runbot-223306 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278983 Forward-Port-Of: odoo/odoo#277954
Preparation printing from mobile self ordering was made by sending a notification in the bus to the PoS. This logic was removed in odoo/odoo#265569, we reintroduce it to allow printing again.
Original PR description
Preparation printing from mobile self ordering was made by sending a notification in the bus to the PoS. This logic was removed in odoo/odoo#265569, we reintroduce it to allow printing again.
Documentation and clarification updates
Description of the issue/feature this PR addresses: Add the Odoo Corporate Contributor License Agreement for bobco GmbH and list the employees authorized to contribute on the company's behalf. Current behavior before PR: bobco GmbH does not yet have a corporate CLA in the Odoo repository. Desired behavior after PR is merged: The corporate CLA covers the listed bobco GmbH contributors. Approval and signature status: @philipbr explicitly approved the declaration as an authorized representat
Original PR description
Description of the issue/feature this PR addresses: Add the Odoo Corporate Contributor License Agreement for bobco GmbH and list the employees authorized to contribute on the company's behalf. Current behavior before PR: bobco GmbH does not yet have a corporate CLA in the Odoo repository. Desired behavior after PR is merged: The corporate CLA covers the listed bobco GmbH contributors. Approval and signature status: @philipbr explicitly approved the declaration as an authorized representative of bobco GmbH. The signatory line has been finalized as: `Philip Braun philip@braun.tf https://github.com/philipbr` --- The corporate CLA has been signed by Philip Braun, and the PR guidelines at www.odoo.com/submit-pr have been read. Forward-Port-Of: odoo/odoo#279348
Miscellaneous changes
Backport of [1]. Builder image tests were flaky in full-suite runs because earlier tests left slow requests pending. Bogus snippet thumbnails, obsolete modify_image mock data, and made-up attachment URLs triggered expensive website 404 rendering and starved the browser connection pool. Avoid rendering missing thumbnails, use data URIs or existing static images in fixtures, return the current modify_image response shape, and give the CORS test image explicit dimensions. [1]: https://gith
Original PR description
Backport of [1]. Builder image tests were flaky in full-suite runs because earlier tests left slow requests pending. Bogus snippet thumbnails, obsolete modify_image mock data, and made-up attachment URLs triggered expensive website 404 rendering and starved the browser connection pool. Avoid rendering missing thumbnails, use data URIs or existing static images in fixtures, return the current modify_image response shape, and give the CORS test image explicit dimensions. [1]: https://github.com/odoo/odoo/pull/277424 Forward-Port-Of: odoo/odoo#279314
4 changes
Resolved issues and error corrections
This commit fix the regex used in `street_split` to be more complient. Before: address format was "street_name street_number - street_number2" Now, street_number can be in front of street_name. Format is also less strict, allowing multiple numbers in the street_name without skipping the building number. Linked: https://github.com/odoo/enterprise/pull/121674 task-6317758 Forward-Port-Of: odoo/odoo#271855
Original PR description
This commit fix the regex used in `street_split` to be more complient. Before: address format was "street_name street_number - street_number2" Now, street_number can be in front of street_name. Format is also less strict, allowing multiple numbers in the street_name without skipping the building number. Linked: https://github.com/odoo/enterprise/pull/121674 task-6317758 Forward-Port-Of: odoo/odoo#271855
- `s_three_columns` cards could end up with mismatched heights: `equalizeCardHeights` now measures header height directly instead of deriving it from the already-stretched card container. - Links appeared with a black background: exclude `btn-link` from background-color application. - Background images didn't stretch: pass `preserve_comments` so the DPI-scaling fix comment isn't stripped from the sent email. opw-6044725 --- I confirm I have signed the CLA and read the PR guidelines at w
Original PR description
- `s_three_columns` cards could end up with mismatched heights: `equalizeCardHeights` now measures header height directly instead of deriving it from the already-stretched card container. - Links appeared with a black background: exclude `btn-link` from background-color application. - Background images didn't stretch: pass `preserve_comments` so the DPI-scaling fix comment isn't stripped from the sent email. opw-6044725 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279196 Forward-Port-Of: odoo/odoo#278862
**Steps to reproduce:** 1. Install Sales app and open any sale order 2. In the "Terms and conditions" text area at the bottom, apply the "/Switch direction" command for an empty block **Issue:** The feature doesn't work when you apply it on an empty line **Why this happens:** Before the fix, the switch-direction logic depended on selected text nodes, and effectively ignored empty content nodes. **Fix:** The problem has been fixed in 19.4 as an [IMP] in this commit 9c97fc464ffba5088
Original PR description
**Steps to reproduce:** 1. Install Sales app and open any sale order 2. In the "Terms and conditions" text area at the bottom, apply the "/Switch direction" command for an empty block **Issue:** The feature doesn't work when you apply it on an empty line **Why this happens:** Before the fix, the switch-direction logic depended on selected text nodes, and effectively ignored empty content nodes. **Fix:** The problem has been fixed in 19.4 as an [IMP] in this commit 9c97fc464ffba5088642d7699b3e033c1fcc2564, so this is essentially a backport for that fix. opw-6344750 Forward-Port-Of: odoo/odoo#276536
Steps to reproduce 1. Create two products and assign the same vendor to both in the Purchase tab 2. Create two Sales Orders using the dropship route (one product per order) 3. Generate and merge the corresponding Purchase Orders, then confirm the merged PO 4. Validate the dropship transfer Issue stock.picking.sale_id is a Many2one (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/sale_stock/models/stock.py#L99) computed from procurement.group.sale_id, an
Original PR description
Steps to reproduce 1. Create two products and assign the same vendor to both in the Purchase tab 2. Create two Sales Orders using the dropship route (one product per order) 3. Generate and merge the…
Steps to reproduce 1. Create two products and assign the same vendor to both in the Purchase tab 2. Create two Sales Orders using the dropship route (one product per order) 3. Generate and merge the corresponding Purchase Orders, then confirm the merged PO 4. Validate the dropship transfer Issue stock.picking.sale_id is a Many2one (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/sale_stock/models/stock.py#L99) computed from procurement.group.sale_id, and stock.picking.group_id is a stored related on move_ids.group_id (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/stock/models/stock_picking.py#L186). A single picking can therefore only resolve to one SO. _create_picking (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/purchase_stock/models/purchase_order.py#L290) builds one picking per PO and _prepare_stock_moves assigns every move the merged PO's group_id (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/purchase_stock/models/purchase_order_line.py#L307), so when a merged dropship PO carries lines from multiple SOs every move lands in one picking under the PO group. Only one SO gets linked and the others stay "not fully delivered" even after validation. Solution Override PurchaseOrderLine._prepare_stock_moves to set group_id to the SO's procurement_group_id when sale_line_id is set, so each dropship move is created in its originating SO's procurement group. Override PurchaseOrder._create_picking to detect dropship POs whose order lines span more than one SO and create one picking per SO group by calling _prepare_picking and _create_stock_moves per group. picking.group_id then resolves to the SO group via the stored related field, picking.sale_id points to the right SO, and delivery_status updates correctly on validation. opw-6094608 Forward-Port-Of: odoo/odoo#257823
8 changes
Enhancements to existing features
Steps to reproduce: 1. Create a sales order. 2. Confirm or cancel the order. 3. Share the quotation link. 4. Open the quotation from an incognito window or the customer portal. Issue: - A 'Quotation Viewed by Customer' notification is sent even though the document is no longer an active quotation. Fix: - Only send the notification while the order is in quotation or quotation sent state. opw-6419364
Original PR description
Steps to reproduce: 1. Create a sales order. 2. Confirm or cancel the order. 3. Share the quotation link. 4. Open the quotation from an incognito window or the customer portal. Issue: - A 'Quotation Viewed by Customer' notification is sent even though the document is no longer an active quotation. Fix: - Only send the notification while the order is in quotation or quotation sent state. opw-6419364
Resolved issues and error corrections
Purpose of this PR: - On double click, opening the toolbar is delayed by 300ms to prevent flickering before a potential triple click. - However, mouseup was re-enabling selection tracking (onSelectionChangeActive = true) before the 300ms delay finished. Because browser selectionchange events are dispatched asynchronously after mouseup, they triggered updateToolbar() immediately, bypassing the 300ms delay. - This fix re-enables selection tracking only after the 300ms debounced update actuall
Original PR description
Purpose of this PR: - On double click, opening the toolbar is delayed by 300ms to prevent flickering before a potential triple click. - However, mouseup was re-enabling selection tracking (onSelectionChangeActive = true) before the 300ms delay finished. Because browser selectionchange events are dispatched asynchronously after mouseup, they triggered updateToolbar() immediately, bypassing the 300ms delay. - This fix re-enables selection tracking only after the 300ms debounced update actually finishes. runbot-941543 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The JsonFormatter has two bugs - the ignore list is not working as expected - in 18.0-18.4 the 'test' key is broken This commit add tests to ensure those behavior works as expected While on it, also adds a `additional_record_keys` parameter to allow to specifically add keys to the default list, without having to override the whole list, and add additional default keys (exc_info and test) The previous `ignored_record_keys` default value was possible to remove by calling `JSONFormatte
Original PR description
The JsonFormatter has two bugs - the ignore list is not working as expected - in 18.0-18.4 the 'test' key is broken This commit add tests to ensure those behavior works as expected While on it, also…
The JsonFormatter has two bugs - the ignore list is not working as expected - in 18.0-18.4 the 'test' key is broken This commit add tests to ensure those behavior works as expected While on it, also adds a `additional_record_keys` parameter to allow to specifically add keys to the default list, without having to override the whole list, and add additional default keys (exc_info and test) The previous `ignored_record_keys` default value was possible to remove by calling `JSONFormatter(ignore_record_keys=[])` The purpose was to be able to easily include all keys and ignore the default ingnore list, but this makes the additional blacklisting of a few keys more tedious, and the general usage and implementation more complex `JSONFormatter(ignore_record_keys=[*JSONFormatter.DEFAULT_IGNORED_RECORD_KEYS, 'other key'])` To simplify the logic, **this is not the case anymore**, so to include all keys something like this would be needed `JSONFormatter(additional_record_keys=JSONFormatter.DEFAULT_IGNORED_RECORD_KEYS)` Or an hardcoded list. Forward-Port-Of: odoo/odoo#279049
Issue: --- Fiscal position is wrongly set to `self.env.user.partner_id.country_id` instead of `partner_shipping` country, if `partner_shipping_id` is not changed in the checkout process. Steps: 1- Create two auto detect fiscal positions: France, Germany 2- Set portal user's partner address country to France. 3- Using portal user, shop from website, and create a delivery address. 4- Pay and confirm the order. 5- Using the admin user, you check the SO's FP which is correctly set to
Original PR description
Issue: --- Fiscal position is wrongly set to `self.env.user.partner_id.country_id` instead of `partner_shipping` country, if `partner_shipping_id` is not changed in the checkout process. Steps: 1-…
Issue: --- Fiscal position is wrongly set to `self.env.user.partner_id.country_id` instead of `partner_shipping` country, if `partner_shipping_id` is not changed in the checkout process. Steps: 1- Create two auto detect fiscal positions: France, Germany 2- Set portal user's partner address country to France. 3- Using portal user, shop from website, and create a delivery address. 4- Pay and confirm the order. 5- Using the admin user, you check the SO's FP which is correctly set to Germany. 6- Using portal user, again shop from website, and don't change address. Keep previous shipping address which is Germany. 7- Confirm and pay the order. 8- Using admin user, check the new SO's FP. It's set to France. Cause: --- `_compute_fiscal_position_id` in SO depends on `partner_shipping_id`. When the `partner_shipping_id` is not changed, the fiscal position value set in create will remain. This value is set in `Website._prepare_sale_order_values()`. The `fiscal_position_id` is set to self.fiscal_position_id, which is `_get_fiscal_position(self.env.user.partner_id)`. Fix: --- If the user has already a SO, we can use last SO's shipping address and invoice address to calculate FP in `_prepare_sale_order_values`. opw-6357638 Forward-Port-Of: odoo/odoo#276485
- `s_three_columns` cards could end up with mismatched heights: `equalizeCardHeights` now measures header height directly instead of deriving it from the already-stretched card container. - Links appeared with a black background: exclude `btn-link` from background-color application. - Background images didn't stretch: pass `preserve_comments` so the DPI-scaling fix comment isn't stripped from the sent email. opw-6044725 --- I confirm I have signed the CLA and read the PR guidelines at w
Original PR description
- `s_three_columns` cards could end up with mismatched heights: `equalizeCardHeights` now measures header height directly instead of deriving it from the already-stretched card container. - Links appeared with a black background: exclude `btn-link` from background-color application. - Background images didn't stretch: pass `preserve_comments` so the DPI-scaling fix comment isn't stripped from the sent email. opw-6044725 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279196 Forward-Port-Of: odoo/odoo#278862
Use "VAT" instead of "TAX" for the default UK tax groups. Also set "Subtotal" as their preceding subtotal label so that it replaces "Untaxed Amount". task-[6413495](https://www.odoo.com/odoo/project/967/tasks/6413495) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
Use "VAT" instead of "TAX" for the default UK tax groups. Also set "Subtotal" as their preceding subtotal label so that it replaces "Untaxed Amount". task-[6413495](https://www.odoo.com/odoo/project/967/tasks/6413495) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Miscellaneous changes
**Steps to reproduce:** - Install Survey app - Create a survey - Share as e-mail - Add some text in the body/subject - Modify recipients - The added text is automatically reset **Issue:** Behavior was previously introduced to match the content of the composer body/subject to the recipient language. If there was only one language among the recipients it automatically adapted the template and changed the rendered language (which also refreshed the content). This logic was trigge
Original PR description
**Steps to reproduce:** - Install Survey app - Create a survey - Share as e-mail - Add some text in the body/subject - Modify recipients - The added text is automatically reset **Issue:** Behavior…
**Steps to reproduce:** - Install Survey app - Create a survey - Share as e-mail - Add some text in the body/subject - Modify recipients - The added text is automatically reset **Issue:** Behavior was previously introduced to match the content of the composer body/subject to the recipient language. If there was only one language among the recipients it automatically adapted the template and changed the rendered language (which also refreshed the content). This logic was triggered by a depends on `partner_ids` and triggered the compute on every recipient changes which led to the subject/body reset. **Fix:** Revert commit: https://github.com/odoo/odoo/commit/b7bbb7b21f4848323666230b518cad9459726f67 in 18.0+ Also adapt commit: https://github.com/odoo/odoo/commit/c6f19e89cb6019e7dbaadbc7427fbb6ddd5661ed to avoid mixed language in resulting mail when the composer was modified We could also try to prevent the compute when the subject or body is already modified instead of removing its logic. opw-6020245
The government has held off the `shipToGSTIN` changes until further notice. https://services.gst.gov.in/services/advisoryandreleases/read/668 Hence, this PR reverts those changes. task-6431622 ref - https://github.com/odoo/odoo/pull/266397 Forward-Port-Of: odoo/odoo#279414
Original PR description
The government has held off the `shipToGSTIN` changes until further notice. https://services.gst.gov.in/services/advisoryandreleases/read/668 Hence, this PR reverts those changes. task-6431622 ref - https://github.com/odoo/odoo/pull/266397 Forward-Port-Of: odoo/odoo#279414
4 changes
Resolved issues and error corrections
Steps to reproduce: - Install employees and attendance app - Make sure there are 2 companies - Make user's employee record for Company B, but not A - Make company A the default company for user - Enable "attendances from backend" setting - Click on the attendance dot (systray) Current Behavior: The dot disappears and you can't check in Expected Behavior: You are able to check in Other bug scenario: If you have employee records in both Company A and Company B, you can check in.
Original PR description
Steps to reproduce: - Install employees and attendance app - Make sure there are 2 companies - Make user's employee record for Company B, but not A - Make company A the default company for user - Enable "attendances from backend" setting - Click on the attendance dot (systray) Current Behavior: The dot disappears and you can't check in Expected Behavior: You are able to check in Other bug scenario: If you have employee records in both Company A and Company B, you can check in. However, you can never check in for Company B as the default company is always selected in the server code opw-6392301
Before this fix, if a pivot table with comparison was inserted, it would not be displayed correctly in the spreadsheet. After this fix, the comparison is completely ignored when inserting a pivot into a spreadsheet. The domain of the comparison is ignored too. Task: 6429681 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
Before this fix, if a pivot table with comparison was inserted, it would not be displayed correctly in the spreadsheet. After this fix, the comparison is completely ignored when inserting a pivot into a spreadsheet. The domain of the comparison is ignored too. Task: 6429681 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
When we create a database with `-i web --skip-auto-install`, we run into CSS compilation errors due to undefined variables `$black` and `$gray-200`. This commit adds these two definitions. opw-6398398
Original PR description
When we create a database with `-i web --skip-auto-install`, we run into CSS compilation errors due to undefined variables `$black` and `$gray-200`. This commit adds these two definitions. opw-6398398
Currently, users encounter a traceback when attempting to print the traceability report for a manufacturing order. ## Steps to produce: - Install Manufacturing without demo data. - Enable Lots & Serial Numbers in Settings. - Create two products: Car and Engine. - Configure Engine to use Unique Serial Number tracking (Inventory →Traceability). - Set the on-hand quantity of Engine to 1 with serial number 0001. - Create a BoM for Car using Engine as a component. - Create and confirm a man
Original PR description
Currently, users encounter a traceback when attempting to print the traceability report for a manufacturing order. ## Steps to produce: - Install Manufacturing without demo data. - Enable Lots &…
Currently, users encounter a traceback when attempting to print the traceability report for a manufacturing order. ## Steps to produce: - Install Manufacturing without demo data. - Enable Lots & Serial Numbers in Settings. - Create two products: Car and Engine. - Configure Engine to use Unique Serial Number tracking (Inventory →Traceability). - Set the on-hand quantity of Engine to 1 with serial number 0001. - Create a BoM for Car using Engine as a component. - Create and confirm a manufacturing order for Car. - Click `Consumed` for the component and click Produce All. - Navigate to Lots & Serial Numbers → Engine → 0001 → Traceability. - Click the arrow next to the manufacturing order reference, then click Print. ## Observed Behavior: An `Arbitrary Uncaught Python Exception` traceback is raised, resulting in a 404 error. ## Root Cause: This issue occurs because, when the user clicks the arrow button in the traceability report, the template [1] invokes the `onClickUpDownStream` function. This function adds the URL `/stock/output_format/stock/active_id` to the context , as shown in [2]. Later, when the user clicks the Print button, `onClickPrint()` [3] constructs the print URL using the `controllerUrl` value by replacing the active model and active ID placeholders with values from the context. However, the URL stored in the context contains `/active_id` instead of `:active_id`. As a result, the placeholder replacement does not occur, leaving the URL unchanged. This causes the print action to use an invalid URL, ultimately resulting in a 404 error. As shown in [4], `controllerUrl` is assigned directly from the context. [1]: https://github.com/odoo/odoo/blob/a398ade607940a281552f8cba2c1cf80bb0e77f6/addons/stock/static/src/client_actions/stock_traceability_report_backend.xml#L52-L56 [2]: https://github.com/odoo/odoo/blob/a398ade607940a281552f8cba2c1cf80bb0e77f6/addons/stock/static/src/client_actions/stock_traceability_report_backend.js#L105-L118 [3]: https://github.com/odoo/odoo/blob/a398ade607940a281552f8cba2c1cf80bb0e77f6/addons/stock/static/src/client_actions/stock_traceability_report_backend.js#L120-L131 [4]: https://github.com/odoo/odoo/blob/a398ade607940a281552f8cba2c1cf80bb0e77f6/addons/stock/static/src/client_actions/stock_traceability_report_backend.js#L53-L55 ## Solution: Pass the correct URL in the context so that the active ID placeholder can be replaced correctly during the print action. This ensures that the generated print URL is valid, allowing the user to print the report without encountering any errors. opw-6372834