Daily updates from Odoo
Thursday, August 6, 2026
244 changes
27 changes
Enhancements to existing features
The feature was never merged on IAP/Internal's side and we now have a new task to move the setting up of the auto-refill from the local db to the IAP server, so the feature is no longer relevant on the client side. Task-6397951 Forward-Port-Of: odoo/odoo#280745 Forward-Port-Of: odoo/odoo#277512
Original PR description
The feature was never merged on IAP/Internal's side and we now have a new task to move the setting up of the auto-refill from the local db to the IAP server, so the feature is no longer relevant on the client side. Task-6397951 Forward-Port-Of: odoo/odoo#280745 Forward-Port-Of: odoo/odoo#277512
This commit adds 3 new `Tax Exemption Reason Code`: - VATEX-FR-F - VATEX-FR-I - VATEX-FR-J task-6333649 Forward-Port-Of: odoo/odoo#280537 Forward-Port-Of: odoo/odoo#278086
Original PR description
This commit adds 3 new `Tax Exemption Reason Code`: - VATEX-FR-F - VATEX-FR-I - VATEX-FR-J task-6333649 Forward-Port-Of: odoo/odoo#280537 Forward-Port-Of: odoo/odoo#278086
Resolved issues and error corrections
### Issue: A user who can modify `tax_exigibility` but does not have `account.group_account_readonly` is blocked from switching to `on_payment` There is no way to complete the operation as the account field is not visible and cannot be filled before saving ### Cause: When `tax_exigibility` is set to `on_payment`, the view expects `cash_basis_transition_account_id` to be filled before saving`_constrains_cash_basis_transition_account` then validates that the account is reconcilable `cas
Original PR description
### Issue: A user who can modify `tax_exigibility` but does not have `account.group_account_readonly` is blocked from switching to `on_payment` There is no way to complete the operation as the…
### Issue: A user who can modify `tax_exigibility` but does not have `account.group_account_readonly` is blocked from switching to `on_payment` There is no way to complete the operation as the account field is not visible and cannot be filled before saving ### Cause: When `tax_exigibility` is set to `on_payment`, the view expects `cash_basis_transition_account_id` to be filled before saving`_constrains_cash_basis_transition_account` then validates that the account is reconcilable `cash_basis_transition_account_id` was restricted to `account.group_account_readonly`, hiding it from other users The field is never rendered, so it cannot be filled The `required` constraint is never evaluated client-side and `_constrains_cash_basis_transition_account` raises a `ValidationError` on save because the account is empty There is no reason to restrict `cash_basis_transition_account_id` independently — if a user can modify `tax_exigibility`, they must also be able to set the linked account ### Steps to reproduce: - Install `account` - Enable Cash Basis in Settings (On RunBot ensure no default account is set) - Enable Developer Mode in Settings - Go to Settings > Users & Companies > Users - Open the current user and disable both: `Show Accounting Features - Readonly` and `Show Full Accounting Features` (if set) - Go to Invoicing > Configuration > Taxes - Open any tax and go to Advanced Options - Change Tax Exigibility to Based on Payment Before the fix, the account selector is not displayed and saving raises an error opw-6359173 Forward-Port-Of: odoo/odoo#274728
Before this commit, the `empty a many2one field in list view` test sometimes failed, because the many2one value wasn't correctly unset (`first record` was selected). This happened because we cleared the input and automatically validated (typically with tab). However, it could happen that the validation occurred after the dropdown was opened, so the first value of the dropdown was selected. As a matter of fact, adding `await runAllTimers()` after clearing the input is a way to make the test fail
Original PR description
Before this commit, the `empty a many2one field in list view` test sometimes failed, because the many2one value wasn't correctly unset (`first record` was selected). This happened because we cleared…
Before this commit, the `empty a many2one field in list view` test sometimes failed, because the many2one value wasn't correctly unset (`first record` was selected). This happened because we cleared the input and automatically validated (typically with tab). However, it could happen that the validation occurred after the dropdown was opened, so the first value of the dropdown was selected. As a matter of fact, adding `await runAllTimers()` after clearing the input is a way to make the test fail deterministically. This commit avoids the issue by emptying the many2one without validation, so it basically only set the input value to the empty string, but doesn't tab/enter or anything else, hence it never selects an unwanted value. runbot error-941430 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#280351
If the badge selection widget value is false, you get an error as it cannot includes in false. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280678
Original PR description
If the badge selection widget value is false, you get an error as it cannot includes in false. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280678
The tracking field was removed from point_of_sale in https://github.com/odoo/odoo/pull/241368 However, forward ports may still keep the field in fixes prior to 19.3 like here in https://github.com/odoo/odoo/pull/279952 This breaks silently because issues only occur when stock is not installed so the forward-port build won't fail but some nightly builds will. runbot-error-944823 Forward-Port-Of: odoo/odoo#280716
Original PR description
The tracking field was removed from point_of_sale in https://github.com/odoo/odoo/pull/241368 However, forward ports may still keep the field in fixes prior to 19.3 like here in https://github.com/odoo/odoo/pull/279952 This breaks silently because issues only occur when stock is not installed so the forward-port build won't fail but some nightly builds will. runbot-error-944823 Forward-Port-Of: odoo/odoo#280716
This is rather an attempt of fix, as we couldn't reproduce the error locally or in a multi build., so we have no guarantee that this strenghtens the test. The test sometimes fails as `.o_crop_icon` can't be found within 200ms. Before that, we wait for the video element to be ready (we rely on a patch of the `isVideoReady` method of the component to know that the video is ready). Once it is, the isReady flag in the state is set to true and the CropOverlay component renders its `o_crop_icon` el
Original PR description
This is rather an attempt of fix, as we couldn't reproduce the error locally or in a multi build., so we have no guarantee that this strenghtens the test. The test sometimes fails as `.o_crop_icon`…
This is rather an attempt of fix, as we couldn't reproduce the error locally or in a multi build., so we have no guarantee that this strenghtens the test. The test sometimes fails as `.o_crop_icon` can't be found within 200ms. Before that, we wait for the video element to be ready (we rely on a patch of the `isVideoReady` method of the component to know that the video is ready). Once it is, the isReady flag in the state is set to true and the CropOverlay component renders its `o_crop_icon` element. Our guess is that we may sometimes early return in `isVideoReady`, because the component has been destroyed (a new rendering might be on the way). To ensure that we don't take that as the ready signal in the test, we now only consider that we're ready if isVideoReady returned true (i.e. no early return). runbot error-241798 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#280329
When a customer invoice is digitized through OCR, the salesperson may be set to the "Public User" instead of the internal user who uploaded the document. Steps to reproduce: - Upload a PDF invoice of an existing customer - Send the PDF to OCR - Reload the page Issue: Observe the Salesperson field: it is set to the Public User. Analysis: This occurs because when the partner is filled in, the compute of the salesperson will trigger. On SaaS this happens through the extraction c
Original PR description
When a customer invoice is digitized through OCR, the salesperson may be set to the "Public User" instead of the internal user who uploaded the document. Steps to reproduce: - Upload a PDF invoice of an existing customer - Send the PDF to OCR - Reload the page Issue: Observe the Salesperson field: it is set to the Public User. Analysis: This occurs because when the partner is filled in, the compute of the salesperson will trigger. On SaaS this happens through the extraction completion webhook a public route processed in sudo. that does not change the current user (public user). As self.env.user is the fallback of the compute, it may be set as salesperson. opw-6296330 Forward-Port-Of: odoo/odoo#279724
**PROBLEM** Before this PR, there was no way to handle invoices sent to clients depending from a JST/LGU (local government unit). This PR add support for it. opw-6095581 Forward-Port-Of: odoo/odoo#280377 Forward-Port-Of: odoo/odoo#260367
Original PR description
**PROBLEM** Before this PR, there was no way to handle invoices sent to clients depending from a JST/LGU (local government unit). This PR add support for it. opw-6095581 Forward-Port-Of: odoo/odoo#280377 Forward-Port-Of: odoo/odoo#260367
Issue: --- `code` is hidden in `payment.method` from without dev mode, which cause an validation error when creating a new payment method. opw-6390285 Forward-Port-Of: odoo/odoo#278671
Original PR description
Issue: --- `code` is hidden in `payment.method` from without dev mode, which cause an validation error when creating a new payment method. opw-6390285 Forward-Port-Of: odoo/odoo#278671
Steps to reproduce 1. Go to Manufacturing > Configuration > Settings and enable By-Products 2. Go to Inventory > Configuration > Locations, find the location with type Production and set the Cost of Production account 3. Go to Inventory > Configuration > Product Categories and set the costing method to Standard Price and Inventory Valuation to Perpetual (at invoicing) 4. Set the finished product and byproduct as Storable with a non-zero Cost 5. Create a BoM with a component and a by
Original PR description
Steps to reproduce 1. Go to Manufacturing > Configuration > Settings and enable By-Products 2. Go to Inventory > Configuration > Locations, find the location with type Production and set the Cost of…
Steps to reproduce 1. Go to Manufacturing > Configuration > Settings and enable By-Products 2. Go to Inventory > Configuration > Locations, find the location with type Production and set the Cost of Production account 3. Go to Inventory > Configuration > Product Categories and set the costing method to Standard Price and Inventory Valuation to Perpetual (at invoicing) 4. Set the finished product and byproduct as Storable with a non-zero Cost 5. Create a BoM with a component and a byproduct with a Cost Share % assigned 6. Create and complete a manufacturing order 7. Check the journal entries of the MO: the byproduct entry shows $0 Issue Standard-cost byproduct moves have no price_unit set in either code path of _cal_price, so their journal entries always show $0. When the finished product is standard cost, _cal_price returns early at https://github.com/odoo/odoo/blob/55221db559cda1c61229eecf8493f5fbaee5cd50/addons/mrp_account/models/mrp_production.py#L66-L68 without iterating byproducts at all, so no price_unit is ever set on them. When the finished product is FIFO/AVCO, the byproduct loop at https://github.com/odoo/odoo/blob/55221db559cda1c61229eecf8493f5fbaee5cd50/addons/mrp_account/models/mrp_production.py#L83-L84 only sets price_unit for FIFO/AVCO byproducts. Standard byproducts are skipped, giving them $0 even though their cost_share was already deducted from the finished product, making value disappear from inventory entirely. For standard-cost products the MO has no influence on their value — they always use the standard_price from the product form, regardless of cost_share. Solution In the early-return branch, iterate byproducts: standard ones get standard_price, FIFO/AVCO ones get total_cost * cost_share. In the FIFO/AVCO branch, add the same standard_price fallback so standard byproducts are no longer left at $0 when their cost_share is set. opw-6020065 Forward-Port-Of: odoo/odoo#280614 Forward-Port-Of: odoo/odoo#257472
**Issue** Confirming a SO that generates a batch of MOs from a BoM with a batch size could lead to creating an invalid number of pickings: all the MOs end up sharing a single picking instead of getting one each. **Steps to reproduce** - Use 2-step manufacturing - Create a storable product with the MTO + Manufacture routes - Add a BOM that has a batch size of 10 that consumes one component - Create and confirm a SO of 100 units of that product -> 10 MOs are created, but each one points
Original PR description
**Issue** Confirming a SO that generates a batch of MOs from a BoM with a batch size could lead to creating an invalid number of pickings: all the MOs end up sharing a single picking instead of…
**Issue** Confirming a SO that generates a batch of MOs from a BoM with a batch size could lead to creating an invalid number of pickings: all the MOs end up sharing a single picking instead of getting one each. **Steps to reproduce** - Use 2-step manufacturing - Create a storable product with the MTO + Manufacture routes - Add a BOM that has a batch size of 10 that consumes one component - Create and confirm a SO of 100 units of that product -> 10 MOs are created, but each one points to the same "Pick Components" transfer instead of getting its own. **Cause** This commit dd6ee071f949752d31497d9f975ba7fc41ebcd98 batches the confirm of productions: https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/mrp/models/stock_rule.py#L120 thus `assign_picking` is called in batches: https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/mrp/models/mrp_production.py#L1653 https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1736-L1737 https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1550-L1556 since, the `reference_ids` are the same for each MO/stock.move (they all come from the same procurement): https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1712-L1713 Consequently, all the moves end up in the same recordset `moves`: https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1527 Creating only one picking: https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1577 opw-6403427 Forward-Port-Of: odoo/odoo#279179
Issue ----- Branch companies can have quants of a product limited to their parent company, but they don't show in the per location report. Steps to reproduce ----- - Create a branch company - Create a WH for the branch - Create a tracked product - Company set to parent only - Switch to the branch company - Add a quant of the product in branch stock - Open Inventory > Reporting > Locations > The product is not shown although there is a quant in the branch Cause ----- The m
Original PR description
Issue ----- Branch companies can have quants of a product limited to their parent company, but they don't show in the per location report. Steps to reproduce ----- - Create a branch company - Create…
Issue ----- Branch companies can have quants of a product limited to their parent company, but they don't show in the per location report. Steps to reproduce ----- - Create a branch company - Create a WH for the branch - Create a tracked product - Company set to parent only - Switch to the branch company - Add a quant of the product in branch stock - Open Inventory > Reporting > Locations > The product is not shown although there is a quant in the branch Cause ----- The menu button triggers `action_view_quants` https://github.com/odoo/odoo/blob/03a3662212f094158f885ae6545009fd0a74d3cb/addons/stock/views/stock_quant_views.xml#L493-L495 https://github.com/odoo/odoo/blob/03a3662212f094158f885ae6545009fd0a74d3cb/addons/stock/models/stock_quant.py#L399-L402 The problem here comes from the fact that in `_get_quants_action`, we limit the products to those of only the active companies, instead of allowing to view those of parent companies aswell. https://github.com/odoo/odoo/blob/03a3662212f094158f885ae6545009fd0a74d3cb/addons/stock/models/stock_quant.py#L1330 Such a change works because the domain is specifically for the product's (`product_id.company_id`) and not the location's. ----- Ticket: opw-6131525 Forward-Port-Of: odoo/odoo#280083 Forward-Port-Of: odoo/odoo#277531
When you refuse an applicant, and there is a survey user_input linked, you are not able to do it because applicant officers don't have access 'write' on the model. So we do it in sudo. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280600
Original PR description
When you refuse an applicant, and there is a survey user_input linked, you are not able to do it because applicant officers don't have access 'write' on the model. So we do it in sudo. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280600
A user with role Inventory/User cannot validate the dropship of a product with an Average Cost (AVCO) Costing Method Steps to reproduce: 1. Install sale_management, stock_dropshipping and stock_landed_costs module 2. Go to Sales > Configuration > Categories and change Furniture / Office's Costing Method to Average Cost (AVCO) 3. Go to Settings > Users and set Marc Demo's role on Purchase to User 3. Log in as Marc Demo 4. Create and confirm a quotation for customer Acme Corporation with p
Original PR description
A user with role Inventory/User cannot validate the dropship of a product with an Average Cost (AVCO) Costing Method Steps to reproduce: 1. Install sale_management, stock_dropshipping and…
A user with role Inventory/User cannot validate the dropship of a product with an Average Cost (AVCO) Costing Method Steps to reproduce: 1. Install sale_management, stock_dropshipping and stock_landed_costs module 2. Go to Sales > Configuration > Categories and change Furniture / Office's Costing Method to Average Cost (AVCO) 3. Go to Settings > Users and set Marc Demo's role on Purchase to User 3. Log in as Marc Demo 4. Create and confirm a quotation for customer Acme Corporation with product Large Cabinet (Dropship route and AVCO costing method) 5. Go to the related purchase order and confirm it 6. Go to the related dropship and validate it 7. An access error is raised Issue: Validating a dropship recomputes the cost of the product and reads `stock.valuation.adjustment.lines` https://github.com/odoo/odoo/blob/cb7b3de6cea07464bcadd1325f52533d34ce09bc/addons/stock_landed_costs/models/stock_move.py#L11 But only Inventory/Administrator have read access to these records https://github.com/odoo/odoo/blob/cb7b3de6cea07464bcadd1325f52533d34ce09bc/addons/stock_landed_costs/security/ir.model.access.csv#L4 Solution: Call `_get_landed_cost` with `.sudo()` in order to update the cost even though the user has no landed costs access opw-6366844 Forward-Port-Of: odoo/odoo#280521 Forward-Port-Of: odoo/odoo#276285
Before this commit: The field selector was not wide enough to fill the available space. Task: 6320505 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
Original PR description
Before this commit: The field selector was not wide enough to fill the available space. Task: 6320505 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
Steps to reproduce the error: (Python Version: 3.14.X) - Install ``accounting_firm`` industry with demo data Code for server action to generate the error: ```py for i in [1]: try: pass except Exception: pass if i: pass ``` Traceback: ```py ValueError: forbidden opcode(s) in'...': JUMP_BACKWARD_NO_INTERRUPT ``` https://github.com/odoo/industry/blob/701f7595453772e42ce72aa75df346a504e5bd82/accounting_firm/demo/ir_actions_server.xml#L105-L10
Original PR description
Steps to reproduce the error: (Python Version: 3.14.X) - Install ``accounting_firm`` industry with demo data Code for server action to generate the error: ```py for i in [1]: try: pass except…
Steps to reproduce the error: (Python Version: 3.14.X)
- Install ``accounting_firm`` industry with demo data
Code for server action to generate the error:
```py
for i in [1]:
try:
pass
except Exception:
pass
if i:
pass
```
Traceback:
```py
ValueError: forbidden opcode(s) in'...': JUMP_BACKWARD_NO_INTERRUPT
```
https://github.com/odoo/industry/blob/701f7595453772e42ce72aa75df346a504e5bd82/accounting_firm/demo/ir_actions_server.xml#L105-L108
The server action contains a ``for`` loop with a ``try/except`` block followed by additional statements in the loop body,
this combination generates the ``JUMP_BACKWARD_NO_INTERRUPT`` opcode, which is not included in ``_SAFE_OPCODES`` at [1].
When the server action is evaluated by ``safe_eval``, it calls the ``assert_valid_codeobj`` method, which validates the compiled bytecode against ``_SAFE_OPCODES``. Since ``JUMP_BACKWARD_NO_INTERRUPT`` is not present in the allowed opcodes, ``assert_valid_codeobj()`` raises a ``ValueError`` at [2] before the server action is executed .
Solution:
``JUMP_BACKWARD_NO_INTERRUPT`` opcode is added in the ``_SAFE_OPCODES`` and it is also added in the ``_SAFE_QWEB_OPCODES``.
It was added in Python 3.11: https://docs.python.org/3/whatsnew/3.11.html#new-opcodes
``JUMP_BACKWARD_NO_INTERRUPT`` is a control-flow opcode that only changes
the interpreter's execution flow by jumping back to a previous instruction.
It is the equivalent to ``JUMP_BACKWARD`` opcode. Its only semantic difference is
that the interpreter does not perform an interrupt check at that instruction.
It does not introduce any new capabilities or perform operations such as
attribute access, imports, function calls, or object creation.
Ref: https://docs.python.org/3.12/library/dis.html#opcode-JUMP_BACKWARD_NO_INTERRUPT
Similar commit that adds some necessary opcodes:
https://github.com/odoo/odoo/commit/86498d24946e510025add5d24ef0d4bcce8ad05f
[1]: https://github.com/odoo/odoo/blob/2ccbc4660077bd48529e9de43d4309fbfafc75ca/odoo/tools/safe_eval.py#L135
[2]: https://github.com/odoo/odoo/blob/2ccbc4660077bd48529e9de43d4309fbfafc75ca/odoo/tools/safe_eval.py#L244-L246
sentry-7614026125
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#277192### Issue: A partner with VAT set to '/' incorrectly matches a fiscal position with `VAT required`, instead of one without The '/' value is the placeholder suggested by the UI to indicate that the partner is known to have no VAT, but it was treated as a valid VAT by the fiscal position matching logic ### Cause: `_get_fpos_ranking_functions` uses `_get_vat_valid` to rank fiscal positions based on VAT presence `_get_vat_valid` returned `True` for any non-empty VAT value, including '/' Th
Original PR description
### Issue: A partner with VAT set to '/' incorrectly matches a fiscal position with `VAT required`, instead of one without The '/' value is the placeholder suggested by the UI to indicate that the…
### Issue: A partner with VAT set to '/' incorrectly matches a fiscal position with `VAT required`, instead of one without The '/' value is the placeholder suggested by the UI to indicate that the partner is known to have no VAT, but it was treated as a valid VAT by the fiscal position matching logic ### Cause: `_get_fpos_ranking_functions` uses `_get_vat_valid` to rank fiscal positions based on VAT presence `_get_vat_valid` returned `True` for any non-empty VAT value, including '/' The '/' case was not excluded, causing it to be treated as a valid VAT number ### Steps to reproduce: - Install `account` - Create two fiscal positions with auto-apply: -- Name: FP VAT, VAT required: True, sequence: 1 -- Name: FP no VAT, VAT required: False, sequence: 2 - Create a partner with VAT: '/' - Create an Invoice for that partner and check the Fiscal Position Before the fix, `FP VAT` is selected instead of `FP no VAT` opw-6204531 Forward-Port-Of: odoo/odoo#280494 Forward-Port-Of: odoo/odoo#280065
## Issue When logging timesheet from the *Recorded* smart button on a Sale Order containing multiple service items, the recorded hours will be added to the first sale order line, regardless of the task ID set on the timesheet entries. ## Steps to reproduce 1. Install *Sales Timesheet* (`sale_timesheet`) 2. Create a Product P: - *Product Type*: Service - *Create on Order*: Task - *Project*: Any 3. Create a SO: - *Customer*: Any - Add the product P on two different
Original PR description
## Issue When logging timesheet from the *Recorded* smart button on a Sale Order containing multiple service items, the recorded hours will be added to the first sale order line, regardless of the…
## Issue
When logging timesheet from the *Recorded* smart button on a Sale Order containing multiple service items, the recorded hours will be added to the first sale order line, regardless of the task ID set on the timesheet entries.
## Steps to reproduce
1. Install *Sales Timesheet* (`sale_timesheet`)
2. Create a Product P:
- *Product Type*: Service
- *Create on Order*: Task
- *Project*: Any
3. Create a SO:
- *Customer*: Any
- Add the product P on two different lines and give them two different descriptions D1 and D2
- Confirm the SO, this will create two tasks with the names D1 and D2
4. On the SO, click the *Recorded* smart button and create two entries:
1. Task D1, 2 hours spent
2. Tsk D2, 3 hours spent
5. **Back on the SO, there are 5 hours registered for the first SOL (with the description D1), which does not match the entries we created from the smart button.**
It is worth noting that when we create the Timesheets entries from the project itself (instead of the SO's smart button), the hours are correctly distributed among the different SOLs.
## Cause
The SOL linked to the timesheet entry (`account.analytic.line`) is computed by `_compute_so_line`:
https://github.com/odoo/odoo/blob/8b102f500f5a122e99b07a08cc43814e7c6f0f75/addons/sale_timesheet/models/hr_timesheet.py#L79-L82
This method sets the correct SOL under the condition that `is_so_line_edited` is False and `_is_no_billed()` returns True.
When opening the *Recorded* smart button from a SO, the `is_so_line_edited` is set to True by default, even if no SOL was modified.
https://github.com/odoo/odoo/blob/8b102f500f5a122e99b07a08cc43814e7c6f0f75/addons/sale_timesheet/models/sale_order.py#L113-L117
As that value is never set to False, when trying to compute the SOL for the timesheet entry, the entry is skipped and the default SOL (which is the first one) is used instead.
opw-6133473
Forward-Port-Of: odoo/odoo#274759Before this commit, in some cases, the order created for printing cash move was saved to the IndexedDB and then later loaded from IndexedDB, which caused the order gets synced to the backend but missing some required fields, like preset or pricelist. opw-5969602 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262248
Original PR description
Before this commit, in some cases, the order created for printing cash move was saved to the IndexedDB and then later loaded from IndexedDB, which caused the order gets synced to the backend but missing some required fields, like preset or pricelist. opw-5969602 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262248
When an invoice is created with "Invoice Overages" selected but not all delivered amounts are included, and a second invoice is then created without "Invoice Overages" selected, the system generates a credit note Steps to reproduce: 1. Install Sales and Project 2. Go to Sales > Products and create a product "test" with Product Type: Service, Create on Order: Project & Task and Invoicing Policy: Prepaid/Fixed Price 3. Create a new quotation for any customer with one unit of product test and
Original PR description
When an invoice is created with "Invoice Overages" selected but not all delivered amounts are included, and a second invoice is then created without "Invoice Overages" selected, the system generates…
When an invoice is created with "Invoice Overages" selected but not all delivered amounts are included, and a second invoice is then created without "Invoice Overages" selected, the system generates a credit note Steps to reproduce: 1. Install Sales and Project 2. Go to Sales > Products and create a product "test" with Product Type: Service, Create on Order: Project & Task and Invoicing Policy: Prepaid/Fixed Price 3. Create a new quotation for any customer with one unit of product test and confirm it 4. Change the quantity delivered to 5 5. Click on Create Invoice and then Create Draft 6. Change the quantity to 3 and confirm 7. Go back to the sale order 8. Click on Create Invoice and uncheck Invoice Overages then click on Create Draft 9. A credit note is created even though there is nothing to invoice since Invoice Overages was disabled Issue: There is no mechanism to prevent the creation of an invoice if we set Invoice Overages to false Solution: Prevent invoice creation if Invoice Overages is set to False. Also had to adapt `_compute_invoice_overages` to make it consistent with its inverse method while keeping `allow_invoice_overages` as the default value. opw-6356807
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 Forward-Port-Of: odoo/odoo#279753 Forward-Port-Of: odoo/odoo#279287
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 Forward-Port-Of: odoo/odoo#279753 Forward-Port-Of: odoo/odoo#279287
Before this commit, this test sometimes failed because it couldn't find a dialog containing "camera" within 200ms. In the test scenario, we click to open the BarcodeDialog, which uses the BarcodeVideoScanner. The latter, in its `onMounted`, checks whether it has the necessary permission, which isn't the case as the `getUserMedia` function is mocked in the test to return a rejected promise. As a consequence, the `onError` callback given in props is called, which changes the state of the parent
Original PR description
Before this commit, this test sometimes failed because it couldn't find a dialog containing "camera" within 200ms. In the test scenario, we click to open the BarcodeDialog, which uses the…
Before this commit, this test sometimes failed because it couldn't find a dialog containing "camera" within 200ms. In the test scenario, we click to open the BarcodeDialog, which uses the BarcodeVideoScanner. The latter, in its `onMounted`, checks whether it has the necessary permission, which isn't the case as the `getUserMedia` function is mocked in the test to return a rejected promise. As a consequence, the `onError` callback given in props is called, which changes the state of the parent component, which re-renders itself so display "Unable to access camera" instead of the BarcodeVideoScanner. To make this test more robust, we do 2 things: 1) load the zxing library before running the test, which avoids the BarcodeVideoScanner component to load it in onWillStart. 2) explicitly wait for the 2 animationFrames, as in the scenario, we must wait for the BarcodeDialog to be rendered twice, and those renderings are now synchronous. runbot error-237933 Forward-Port-Of: odoo/odoo#280613
Steps to reproduce ------------------ 1. Set the company document layout to DIN5008 2. Open a delivery and print the delivery slip The title is missing on the DIN5008 layout, we only have the reference `WH/OUT/00001`. What happens ------------ The DIN5008 layout hides the body title with css and prints its own `h2` instead, from the `din5008_document_title` variable, and uses `o.name` (the picking number) when this variable is not set. The commit 0058d1cf7655 added the title on the
Original PR description
Steps to reproduce ------------------ 1. Set the company document layout to DIN5008 2. Open a delivery and print the delivery slip The title is missing on the DIN5008 layout, we only have the reference `WH/OUT/00001`. What happens ------------ The DIN5008 layout hides the body title with css and prints its own `h2` instead, from the `din5008_document_title` variable, and uses `o.name` (the picking number) when this variable is not set. The commit 0058d1cf7655 added the title on the standard delivery report with `picking_type_id._get_code_report_name()`, but `l10n_din5008_stock` was not updated to set `din5008_document_title`, so on DIN5008 we only get the number. The fix ------- We set it the same way as the other layouts, hence we get back the full title `Delivery Note WH/OUT/00001`. opw-6299248 Forward-Port-Of: odoo/odoo#277444
The tour deletes the five "brol" menu items, then immediately drags `new_nested_menu` onto `new_menu`. Each delete step only waits for the next item's delete button, which is already in the DOM, so the removals may still be un-rendered when the drag starts, shifting the rows under it and leaving `new_nested_menu` unnested. This commit waits for the deleted items to be gone before dragging. runbot-944576
Original PR description
The tour deletes the five "brol" menu items, then immediately drags `new_nested_menu` onto `new_menu`. Each delete step only waits for the next item's delete button, which is already in the DOM, so the removals may still be un-rendered when the drag starts, shifting the rows under it and leaving `new_nested_menu` unnested. This commit waits for the deleted items to be gone before dragging. runbot-944576
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 Forward-Port-Of: odoo/odoo#280162 Forward-Port-Of: odoo/odoo#254090
load_data() reads product.pricelist.item_ids as a field, which applies _base_domain_item_ids()'s dotted active conditions. Since this runs as the cashier, never sudo, the ORM injects ir.rules into those conditions, forcing a non-hashable subquery that Postgres re-scans once per pricelist item. Cost scales with items times catalog size, freezing session opening on large catalogs. product.pricelist.item is already loaded separately via a plain, indexed pricelist_id domain. Reuse it to build ite
Original PR description
load_data() reads product.pricelist.item_ids as a field, which applies _base_domain_item_ids()'s dotted active conditions. Since this runs as the cashier, never sudo, the ORM injects ir.rules into those conditions, forcing a non-hashable subquery that Postgres re-scans once per pricelist item. Cost scales with items times catalog size, freezing session opening on large catalogs.
product.pricelist.item is already loaded separately via a plain, indexed pricelist_id domain. Reuse it to build item_ids instead of reading the field, avoiding the join/subquery entirely.
before after speedup
item_ids read 475.8s 2.44s ~195x
load_data() (full) unbounded 8.7s hang -> ok
opw-6391847
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#27725420 changes
Enhancements to existing features
The feature was never merged on IAP/Internal's side and we now have a new task to move the setting up of the auto-refill from the local db to the IAP server, so the feature is no longer relevant on the client side. Task-6397951 Forward-Port-Of: odoo/odoo#277512
Original PR description
The feature was never merged on IAP/Internal's side and we now have a new task to move the setting up of the auto-refill from the local db to the IAP server, so the feature is no longer relevant on the client side. Task-6397951 Forward-Port-Of: odoo/odoo#277512
This commit adds 3 new `Tax Exemption Reason Code`: - VATEX-FR-F - VATEX-FR-I - VATEX-FR-J task-6333649 Forward-Port-Of: odoo/odoo#280537 Forward-Port-Of: odoo/odoo#278086
Original PR description
This commit adds 3 new `Tax Exemption Reason Code`: - VATEX-FR-F - VATEX-FR-I - VATEX-FR-J task-6333649 Forward-Port-Of: odoo/odoo#280537 Forward-Port-Of: odoo/odoo#278086
Resolved issues and error corrections
When a customer invoice is digitized through OCR, the salesperson may be set to the "Public User" instead of the internal user who uploaded the document. Steps to reproduce: - Upload a PDF invoice of an existing customer - Send the PDF to OCR - Reload the page Issue: Observe the Salesperson field: it is set to the Public User. Analysis: This occurs because when the partner is filled in, the compute of the salesperson will trigger. On SaaS this happens through the extraction c
Original PR description
When a customer invoice is digitized through OCR, the salesperson may be set to the "Public User" instead of the internal user who uploaded the document. Steps to reproduce: - Upload a PDF invoice of an existing customer - Send the PDF to OCR - Reload the page Issue: Observe the Salesperson field: it is set to the Public User. Analysis: This occurs because when the partner is filled in, the compute of the salesperson will trigger. On SaaS this happens through the extraction completion webhook a public route processed in sudo. that does not change the current user (public user). As self.env.user is the fallback of the compute, it may be set as salesperson. opw-6296330 Forward-Port-Of: odoo/odoo#279724
### 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#279616 Forward-Port-Of: odoo/odoo#278838
**PROBLEM** Before this PR, there was no way to handle invoices sent to clients depending from a JST/LGU (local government unit). This PR add support for it. opw-6095581 Forward-Port-Of: odoo/odoo#280377 Forward-Port-Of: odoo/odoo#260367
Original PR description
**PROBLEM** Before this PR, there was no way to handle invoices sent to clients depending from a JST/LGU (local government unit). This PR add support for it. opw-6095581 Forward-Port-Of: odoo/odoo#280377 Forward-Port-Of: odoo/odoo#260367
Steps to reproduce 1. Go to Manufacturing > Configuration > Settings and enable By-Products 2. Go to Inventory > Configuration > Locations, find the location with type Production and set the Cost of Production account 3. Go to Inventory > Configuration > Product Categories and set the costing method to Standard Price and Inventory Valuation to Perpetual (at invoicing) 4. Set the finished product and byproduct as Storable with a non-zero Cost 5. Create a BoM with a component and a by
Original PR description
Steps to reproduce 1. Go to Manufacturing > Configuration > Settings and enable By-Products 2. Go to Inventory > Configuration > Locations, find the location with type Production and set the Cost of…
Steps to reproduce 1. Go to Manufacturing > Configuration > Settings and enable By-Products 2. Go to Inventory > Configuration > Locations, find the location with type Production and set the Cost of Production account 3. Go to Inventory > Configuration > Product Categories and set the costing method to Standard Price and Inventory Valuation to Perpetual (at invoicing) 4. Set the finished product and byproduct as Storable with a non-zero Cost 5. Create a BoM with a component and a byproduct with a Cost Share % assigned 6. Create and complete a manufacturing order 7. Check the journal entries of the MO: the byproduct entry shows $0 Issue Standard-cost byproduct moves have no price_unit set in either code path of _cal_price, so their journal entries always show $0. When the finished product is standard cost, _cal_price returns early at https://github.com/odoo/odoo/blob/55221db559cda1c61229eecf8493f5fbaee5cd50/addons/mrp_account/models/mrp_production.py#L66-L68 without iterating byproducts at all, so no price_unit is ever set on them. When the finished product is FIFO/AVCO, the byproduct loop at https://github.com/odoo/odoo/blob/55221db559cda1c61229eecf8493f5fbaee5cd50/addons/mrp_account/models/mrp_production.py#L83-L84 only sets price_unit for FIFO/AVCO byproducts. Standard byproducts are skipped, giving them $0 even though their cost_share was already deducted from the finished product, making value disappear from inventory entirely. For standard-cost products the MO has no influence on their value — they always use the standard_price from the product form, regardless of cost_share. Solution In the early-return branch, iterate byproducts: standard ones get standard_price, FIFO/AVCO ones get total_cost * cost_share. In the FIFO/AVCO branch, add the same standard_price fallback so standard byproducts are no longer left at $0 when their cost_share is set. opw-6020065 Forward-Port-Of: odoo/odoo#280614 Forward-Port-Of: odoo/odoo#257472
**Issue** Confirming a SO that generates a batch of MOs from a BoM with a batch size could lead to creating an invalid number of pickings: all the MOs end up sharing a single picking instead of getting one each. **Steps to reproduce** - Use 2-step manufacturing - Create a storable product with the MTO + Manufacture routes - Add a BOM that has a batch size of 10 that consumes one component - Create and confirm a SO of 100 units of that product -> 10 MOs are created, but each one points
Original PR description
**Issue** Confirming a SO that generates a batch of MOs from a BoM with a batch size could lead to creating an invalid number of pickings: all the MOs end up sharing a single picking instead of…
**Issue** Confirming a SO that generates a batch of MOs from a BoM with a batch size could lead to creating an invalid number of pickings: all the MOs end up sharing a single picking instead of getting one each. **Steps to reproduce** - Use 2-step manufacturing - Create a storable product with the MTO + Manufacture routes - Add a BOM that has a batch size of 10 that consumes one component - Create and confirm a SO of 100 units of that product -> 10 MOs are created, but each one points to the same "Pick Components" transfer instead of getting its own. **Cause** This commit dd6ee071f949752d31497d9f975ba7fc41ebcd98 batches the confirm of productions: https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/mrp/models/stock_rule.py#L120 thus `assign_picking` is called in batches: https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/mrp/models/mrp_production.py#L1653 https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1736-L1737 https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1550-L1556 since, the `reference_ids` are the same for each MO/stock.move (they all come from the same procurement): https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1712-L1713 Consequently, all the moves end up in the same recordset `moves`: https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1527 Creating only one picking: https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1577 opw-6403427 Forward-Port-Of: odoo/odoo#279179
Issue ----- Branch companies can have quants of a product limited to their parent company, but they don't show in the per location report. Steps to reproduce ----- - Create a branch company - Create a WH for the branch - Create a tracked product - Company set to parent only - Switch to the branch company - Add a quant of the product in branch stock - Open Inventory > Reporting > Locations > The product is not shown although there is a quant in the branch Cause ----- The m
Original PR description
Issue ----- Branch companies can have quants of a product limited to their parent company, but they don't show in the per location report. Steps to reproduce ----- - Create a branch company - Create…
Issue ----- Branch companies can have quants of a product limited to their parent company, but they don't show in the per location report. Steps to reproduce ----- - Create a branch company - Create a WH for the branch - Create a tracked product - Company set to parent only - Switch to the branch company - Add a quant of the product in branch stock - Open Inventory > Reporting > Locations > The product is not shown although there is a quant in the branch Cause ----- The menu button triggers `action_view_quants` https://github.com/odoo/odoo/blob/03a3662212f094158f885ae6545009fd0a74d3cb/addons/stock/views/stock_quant_views.xml#L493-L495 https://github.com/odoo/odoo/blob/03a3662212f094158f885ae6545009fd0a74d3cb/addons/stock/models/stock_quant.py#L399-L402 The problem here comes from the fact that in `_get_quants_action`, we limit the products to those of only the active companies, instead of allowing to view those of parent companies aswell. https://github.com/odoo/odoo/blob/03a3662212f094158f885ae6545009fd0a74d3cb/addons/stock/models/stock_quant.py#L1330 Such a change works because the domain is specifically for the product's (`product_id.company_id`) and not the location's. ----- Ticket: opw-6131525 Forward-Port-Of: odoo/odoo#280083 Forward-Port-Of: odoo/odoo#277531
A user with role Inventory/User cannot validate the dropship of a product with an Average Cost (AVCO) Costing Method Steps to reproduce: 1. Install sale_management, stock_dropshipping and stock_landed_costs module 2. Go to Sales > Configuration > Categories and change Furniture / Office's Costing Method to Average Cost (AVCO) 3. Go to Settings > Users and set Marc Demo's role on Purchase to User 3. Log in as Marc Demo 4. Create and confirm a quotation for customer Acme Corporation with p
Original PR description
A user with role Inventory/User cannot validate the dropship of a product with an Average Cost (AVCO) Costing Method Steps to reproduce: 1. Install sale_management, stock_dropshipping and…
A user with role Inventory/User cannot validate the dropship of a product with an Average Cost (AVCO) Costing Method Steps to reproduce: 1. Install sale_management, stock_dropshipping and stock_landed_costs module 2. Go to Sales > Configuration > Categories and change Furniture / Office's Costing Method to Average Cost (AVCO) 3. Go to Settings > Users and set Marc Demo's role on Purchase to User 3. Log in as Marc Demo 4. Create and confirm a quotation for customer Acme Corporation with product Large Cabinet (Dropship route and AVCO costing method) 5. Go to the related purchase order and confirm it 6. Go to the related dropship and validate it 7. An access error is raised Issue: Validating a dropship recomputes the cost of the product and reads `stock.valuation.adjustment.lines` https://github.com/odoo/odoo/blob/cb7b3de6cea07464bcadd1325f52533d34ce09bc/addons/stock_landed_costs/models/stock_move.py#L11 But only Inventory/Administrator have read access to these records https://github.com/odoo/odoo/blob/cb7b3de6cea07464bcadd1325f52533d34ce09bc/addons/stock_landed_costs/security/ir.model.access.csv#L4 Solution: Call `_get_landed_cost` with `.sudo()` in order to update the cost even though the user has no landed costs access opw-6366844 Forward-Port-Of: odoo/odoo#280521 Forward-Port-Of: odoo/odoo#276285
**Steps to reproduce:** - Go to any view where you can send mails (eg sale orders) - Send a first mail to multiple recipients so they are added automatically on the next mail. - Open a new mail, confirm that the recipients are present, add a selectable attachment (eg a PDF), then click on it. - Remove any amount of recipients then send the mail. - You will see that the recipients are added back and the mail is sent to them. **Behavior:** Currently whenever a user clicks on an attachment
Original PR description
**Steps to reproduce:** - Go to any view where you can send mails (eg sale orders) - Send a first mail to multiple recipients so they are added automatically on the next mail. - Open a new mail,…
**Steps to reproduce:**
- Go to any view where you can send mails (eg sale orders)
- Send a first mail to multiple recipients so they are added automatically on the next mail.
- Open a new mail, confirm that the recipients are present, add a selectable attachment (eg a PDF), then click on it.
- Remove any amount of recipients then send the mail.
- You will see that the recipients are added back and the mail is sent to them.
**Behavior:**
Currently whenever a user clicks on an attachment in a mail composer, the systems considers that the user might be trying
to leave the page and will trigger an `urgentSave()`, and further down the line a `web_save()`.
The behavior when a web_save() is triggered is to create a record if there isnt currently one, and otherwise to write the modified values onto the record, using commands.
The recipients for the mail are added by default, which is represented by a list of `[4, id]`add commands, that will be written on the record created in the first `web_save`, however this list is not correctly emptied after the first `_save()`.
If the list is present within `this._changes` then it is correctly cleared, but in the case where no changes were made, the within `this._values['partner_ids']` still contains the commands.
So when we later assign `this.data = { ...this._values };`, `this.data['partner_ids']` now contains our uncleared list of commands.
https://github.com/odoo/odoo/blob/f3e407c6a58abd2ddba42f26fcbd1928da63cb63/addons/web/static/src/model/relational_model/record.js#L1222-L1230
And when we compute changes['partner_ids'] in our next iteration, we find ourselves with our command list again.
https://github.com/odoo/odoo/blob/f3e407c6a58abd2ddba42f26fcbd1928da63cb63/addons/web/static/src/model/relational_model/record.js#L1317-L1322
So when we then try to remove a recipient tag, the new delete command `[3, id]`
just gets canceled out with the already present add command.
And the `write()` in `web_save()` only writes add commands of already present partners, which doesn't do anything.
----
This commit adds a line to ensure commands inside `_values` are cleared
opw-6304713
Forward-Port-Of: odoo/odoo#280533
Forward-Port-Of: odoo/odoo#278876Steps to reproduce: 1. Install Calendar 2. Create a meeting in Calendar in form view 3. Set the video link on it 4. Turn on the debug mode 5. Now, clear the video link Issue: - Traceback ``` Uncaught Promise > Invalid props for component 'CopyButton': 'content' is not a string or object or function ``` Cause: - The 'CopyButton' component expect content to be a string, object or function but receives false. It does not happen in previous versions because in the refector https:/
Original PR description
Steps to reproduce: 1. Install Calendar 2. Create a meeting in Calendar in form view 3. Set the video link on it 4. Turn on the debug mode 5. Now, clear the video link Issue: - Traceback ``` Uncaught…
Steps to reproduce: 1. Install Calendar 2. Create a meeting in Calendar in form view 3. Set the video link on it 4. Turn on the debug mode 5. Now, clear the video link Issue: - Traceback ``` Uncaught Promise > Invalid props for component 'CopyButton': 'content' is not a string or object or function ``` Cause: - The 'CopyButton' component expect content to be a string, object or function but receives false. It does not happen in previous versions because in the refector https://github.com/odoo/odoo/commit/c2f34517b2f9832a498981d0fa17ec39b9739cb6 set the `videocall_location` to false instead of empty string like before https://github.com/odoo/odoo/blob/499420f7062ab467ff6f50b30c547e54c35ae1e9/addons/web/static/src/core/copy_button/copy_button.js#L14 - but any field using the `CopyClipboardChar/CopyClipboardURL` widget passes its raw field value straight through as content. An empty char/text field is represented as false, so whenever such a field becomes empty, CopyClipboardField hands `false` to CopyButton, which fails prop validation (debug mode). Solution: - Fix it at the source: CopyClipboardField's template now falls back to an empty string when the field value is falsy, so CopyButton never receives false but a valid string. opw-6360936 Forward-Port-Of: odoo/odoo#275236
Steps to reproduce the error: (Python Version: 3.14.X) - Install ``accounting_firm`` industry with demo data Code for server action to generate the error: ```py for i in [1]: try: pass except Exception: pass if i: pass ``` Traceback: ```py ValueError: forbidden opcode(s) in'...': JUMP_BACKWARD_NO_INTERRUPT ``` https://github.com/odoo/industry/blob/701f7595453772e42ce72aa75df346a504e5bd82/accounting_firm/demo/ir_actions_server.xml#L105-L10
Original PR description
Steps to reproduce the error: (Python Version: 3.14.X) - Install ``accounting_firm`` industry with demo data Code for server action to generate the error: ```py for i in [1]: try: pass except…
Steps to reproduce the error: (Python Version: 3.14.X)
- Install ``accounting_firm`` industry with demo data
Code for server action to generate the error:
```py
for i in [1]:
try:
pass
except Exception:
pass
if i:
pass
```
Traceback:
```py
ValueError: forbidden opcode(s) in'...': JUMP_BACKWARD_NO_INTERRUPT
```
https://github.com/odoo/industry/blob/701f7595453772e42ce72aa75df346a504e5bd82/accounting_firm/demo/ir_actions_server.xml#L105-L108
The server action contains a ``for`` loop with a ``try/except`` block followed by additional statements in the loop body,
this combination generates the ``JUMP_BACKWARD_NO_INTERRUPT`` opcode, which is not included in ``_SAFE_OPCODES`` at [1].
When the server action is evaluated by ``safe_eval``, it calls the ``assert_valid_codeobj`` method, which validates the compiled bytecode against ``_SAFE_OPCODES``. Since ``JUMP_BACKWARD_NO_INTERRUPT`` is not present in the allowed opcodes, ``assert_valid_codeobj()`` raises a ``ValueError`` at [2] before the server action is executed .
Solution:
``JUMP_BACKWARD_NO_INTERRUPT`` opcode is added in the ``_SAFE_OPCODES`` and it is also added in the ``_SAFE_QWEB_OPCODES``.
It was added in Python 3.11: https://docs.python.org/3/whatsnew/3.11.html#new-opcodes
``JUMP_BACKWARD_NO_INTERRUPT`` is a control-flow opcode that only changes
the interpreter's execution flow by jumping back to a previous instruction.
It is the equivalent to ``JUMP_BACKWARD`` opcode. Its only semantic difference is
that the interpreter does not perform an interrupt check at that instruction.
It does not introduce any new capabilities or perform operations such as
attribute access, imports, function calls, or object creation.
Ref: https://docs.python.org/3.12/library/dis.html#opcode-JUMP_BACKWARD_NO_INTERRUPT
Similar commit that adds some necessary opcodes:
https://github.com/odoo/odoo/commit/86498d24946e510025add5d24ef0d4bcce8ad05f
[1]: https://github.com/odoo/odoo/blob/2ccbc4660077bd48529e9de43d4309fbfafc75ca/odoo/tools/safe_eval.py#L135
[2]: https://github.com/odoo/odoo/blob/2ccbc4660077bd48529e9de43d4309fbfafc75ca/odoo/tools/safe_eval.py#L244-L246
sentry-7614026125
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#277192### Issue: A partner with VAT set to '/' incorrectly matches a fiscal position with `VAT required`, instead of one without The '/' value is the placeholder suggested by the UI to indicate that the partner is known to have no VAT, but it was treated as a valid VAT by the fiscal position matching logic ### Cause: `_get_fpos_ranking_functions` uses `_get_vat_valid` to rank fiscal positions based on VAT presence `_get_vat_valid` returned `True` for any non-empty VAT value, including '/' Th
Original PR description
### Issue: A partner with VAT set to '/' incorrectly matches a fiscal position with `VAT required`, instead of one without The '/' value is the placeholder suggested by the UI to indicate that the…
### Issue: A partner with VAT set to '/' incorrectly matches a fiscal position with `VAT required`, instead of one without The '/' value is the placeholder suggested by the UI to indicate that the partner is known to have no VAT, but it was treated as a valid VAT by the fiscal position matching logic ### Cause: `_get_fpos_ranking_functions` uses `_get_vat_valid` to rank fiscal positions based on VAT presence `_get_vat_valid` returned `True` for any non-empty VAT value, including '/' The '/' case was not excluded, causing it to be treated as a valid VAT number ### Steps to reproduce: - Install `account` - Create two fiscal positions with auto-apply: -- Name: FP VAT, VAT required: True, sequence: 1 -- Name: FP no VAT, VAT required: False, sequence: 2 - Create a partner with VAT: '/' - Create an Invoice for that partner and check the Fiscal Position Before the fix, `FP VAT` is selected instead of `FP no VAT` opw-6204531 Forward-Port-Of: odoo/odoo#280494 Forward-Port-Of: odoo/odoo#280065
## Issue When logging timesheet from the *Recorded* smart button on a Sale Order containing multiple service items, the recorded hours will be added to the first sale order line, regardless of the task ID set on the timesheet entries. ## Steps to reproduce 1. Install *Sales Timesheet* (`sale_timesheet`) 2. Create a Product P: - *Product Type*: Service - *Create on Order*: Task - *Project*: Any 3. Create a SO: - *Customer*: Any - Add the product P on two different
Original PR description
## Issue When logging timesheet from the *Recorded* smart button on a Sale Order containing multiple service items, the recorded hours will be added to the first sale order line, regardless of the…
## Issue
When logging timesheet from the *Recorded* smart button on a Sale Order containing multiple service items, the recorded hours will be added to the first sale order line, regardless of the task ID set on the timesheet entries.
## Steps to reproduce
1. Install *Sales Timesheet* (`sale_timesheet`)
2. Create a Product P:
- *Product Type*: Service
- *Create on Order*: Task
- *Project*: Any
3. Create a SO:
- *Customer*: Any
- Add the product P on two different lines and give them two different descriptions D1 and D2
- Confirm the SO, this will create two tasks with the names D1 and D2
4. On the SO, click the *Recorded* smart button and create two entries:
1. Task D1, 2 hours spent
2. Tsk D2, 3 hours spent
5. **Back on the SO, there are 5 hours registered for the first SOL (with the description D1), which does not match the entries we created from the smart button.**
It is worth noting that when we create the Timesheets entries from the project itself (instead of the SO's smart button), the hours are correctly distributed among the different SOLs.
## Cause
The SOL linked to the timesheet entry (`account.analytic.line`) is computed by `_compute_so_line`:
https://github.com/odoo/odoo/blob/8b102f500f5a122e99b07a08cc43814e7c6f0f75/addons/sale_timesheet/models/hr_timesheet.py#L79-L82
This method sets the correct SOL under the condition that `is_so_line_edited` is False and `_is_no_billed()` returns True.
When opening the *Recorded* smart button from a SO, the `is_so_line_edited` is set to True by default, even if no SOL was modified.
https://github.com/odoo/odoo/blob/8b102f500f5a122e99b07a08cc43814e7c6f0f75/addons/sale_timesheet/models/sale_order.py#L113-L117
As that value is never set to False, when trying to compute the SOL for the timesheet entry, the entry is skipped and the default SOL (which is the first one) is used instead.
opw-6133473
Forward-Port-Of: odoo/odoo#274759Before this commit, in some cases, the order created for printing cash move was saved to the IndexedDB and then later loaded from IndexedDB, which caused the order gets synced to the backend but missing some required fields, like preset or pricelist. opw-5969602 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262248
Original PR description
Before this commit, in some cases, the order created for printing cash move was saved to the IndexedDB and then later loaded from IndexedDB, which caused the order gets synced to the backend but missing some required fields, like preset or pricelist. opw-5969602 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262248
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 Forward-Port-Of: odoo/odoo#279753 Forward-Port-Of: odoo/odoo#279287
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 Forward-Port-Of: odoo/odoo#279753 Forward-Port-Of: odoo/odoo#279287
Before this commit, this test sometimes failed because it couldn't find a dialog containing "camera" within 200ms. In the test scenario, we click to open the BarcodeDialog, which uses the BarcodeVideoScanner. The latter, in its `onMounted`, checks whether it has the necessary permission, which isn't the case as the `getUserMedia` function is mocked in the test to return a rejected promise. As a consequence, the `onError` callback given in props is called, which changes the state of the parent
Original PR description
Before this commit, this test sometimes failed because it couldn't find a dialog containing "camera" within 200ms. In the test scenario, we click to open the BarcodeDialog, which uses the…
Before this commit, this test sometimes failed because it couldn't find a dialog containing "camera" within 200ms. In the test scenario, we click to open the BarcodeDialog, which uses the BarcodeVideoScanner. The latter, in its `onMounted`, checks whether it has the necessary permission, which isn't the case as the `getUserMedia` function is mocked in the test to return a rejected promise. As a consequence, the `onError` callback given in props is called, which changes the state of the parent component, which re-renders itself so display "Unable to access camera" instead of the BarcodeVideoScanner. To make this test more robust, we do 2 things: 1) load the zxing library before running the test, which avoids the BarcodeVideoScanner component to load it in onWillStart. 2) explicitly wait for the 2 animationFrames, as in the scenario, we must wait for the BarcodeDialog to be rendered twice, and those renderings are now synchronous. runbot error-237933 Forward-Port-Of: odoo/odoo#280613
Steps to reproduce ------------------ 1. Set the company document layout to DIN5008 2. Open a delivery and print the delivery slip The title is missing on the DIN5008 layout, we only have the reference `WH/OUT/00001`. What happens ------------ The DIN5008 layout hides the body title with css and prints its own `h2` instead, from the `din5008_document_title` variable, and uses `o.name` (the picking number) when this variable is not set. The commit 0058d1cf7655 added the title on the
Original PR description
Steps to reproduce ------------------ 1. Set the company document layout to DIN5008 2. Open a delivery and print the delivery slip The title is missing on the DIN5008 layout, we only have the reference `WH/OUT/00001`. What happens ------------ The DIN5008 layout hides the body title with css and prints its own `h2` instead, from the `din5008_document_title` variable, and uses `o.name` (the picking number) when this variable is not set. The commit 0058d1cf7655 added the title on the standard delivery report with `picking_type_id._get_code_report_name()`, but `l10n_din5008_stock` was not updated to set `din5008_document_title`, so on DIN5008 we only get the number. The fix ------- We set it the same way as the other layouts, hence we get back the full title `Delivery Note WH/OUT/00001`. opw-6299248 Forward-Port-Of: odoo/odoo#277444
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 Forward-Port-Of: odoo/odoo#280162 Forward-Port-Of: odoo/odoo#254090
load_data() reads product.pricelist.item_ids as a field, which applies _base_domain_item_ids()'s dotted active conditions. Since this runs as the cashier, never sudo, the ORM injects ir.rules into those conditions, forcing a non-hashable subquery that Postgres re-scans once per pricelist item. Cost scales with items times catalog size, freezing session opening on large catalogs. product.pricelist.item is already loaded separately via a plain, indexed pricelist_id domain. Reuse it to build ite
Original PR description
load_data() reads product.pricelist.item_ids as a field, which applies _base_domain_item_ids()'s dotted active conditions. Since this runs as the cashier, never sudo, the ORM injects ir.rules into those conditions, forcing a non-hashable subquery that Postgres re-scans once per pricelist item. Cost scales with items times catalog size, freezing session opening on large catalogs.
product.pricelist.item is already loaded separately via a plain, indexed pricelist_id domain. Reuse it to build item_ids instead of reading the field, avoiding the join/subquery entirely.
before after speedup
item_ids read 475.8s 2.44s ~195x
load_data() (full) unbounded 8.7s hang -> ok
opw-6391847
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#27725412 changes
Resolved issues and error corrections
Bug === Since a4efb745e9f4ba24dfa01f1e17e65f1a7cac90a5 , we cannot insert properties. The reason is that we try to get the field definition from the inserted QWeb expression (eg `object.properties.get('property_product', env['product']).name`) which crash. Task-6311655
Original PR description
Bug
===
Since a4efb745e9f4ba24dfa01f1e17e65f1a7cac90a5 , we cannot insert properties. The reason is that we try to get the field definition from the inserted QWeb expression (eg `object.properties.get('property_product', env['product']).name`) which crash.
Task-6311655### Issue: A user who can modify `tax_exigibility` but does not have `account.group_account_readonly` is blocked from switching to `on_payment` There is no way to complete the operation as the account field is not visible and cannot be filled before saving ### Cause: When `tax_exigibility` is set to `on_payment`, the view expects `cash_basis_transition_account_id` to be filled before saving`_constrains_cash_basis_transition_account` then validates that the account is reconcilable `cas
Original PR description
### Issue: A user who can modify `tax_exigibility` but does not have `account.group_account_readonly` is blocked from switching to `on_payment` There is no way to complete the operation as the…
### Issue: A user who can modify `tax_exigibility` but does not have `account.group_account_readonly` is blocked from switching to `on_payment` There is no way to complete the operation as the account field is not visible and cannot be filled before saving ### Cause: When `tax_exigibility` is set to `on_payment`, the view expects `cash_basis_transition_account_id` to be filled before saving`_constrains_cash_basis_transition_account` then validates that the account is reconcilable `cash_basis_transition_account_id` was restricted to `account.group_account_readonly`, hiding it from other users The field is never rendered, so it cannot be filled The `required` constraint is never evaluated client-side and `_constrains_cash_basis_transition_account` raises a `ValidationError` on save because the account is empty There is no reason to restrict `cash_basis_transition_account_id` independently — if a user can modify `tax_exigibility`, they must also be able to set the linked account ### Steps to reproduce: - Install `account` - Enable Cash Basis in Settings (On RunBot ensure no default account is set) - Enable Developer Mode in Settings - Go to Settings > Users & Companies > Users - Open the current user and disable both: `Show Accounting Features - Readonly` and `Show Full Accounting Features` (if set) - Go to Invoicing > Configuration > Taxes - Open any tax and go to Advanced Options - Change Tax Exigibility to Based on Payment Before the fix, the account selector is not displayed and saving raises an error opw-6359173 Forward-Port-Of: odoo/odoo#274728
Before this commit, the `empty a many2one field in list view` test sometimes failed, because the many2one value wasn't correctly unset (`first record` was selected). This happened because we cleared the input and automatically validated (typically with tab). However, it could happen that the validation occurred after the dropdown was opened, so the first value of the dropdown was selected. As a matter of fact, adding `await runAllTimers()` after clearing the input is a way to make the test fail
Original PR description
Before this commit, the `empty a many2one field in list view` test sometimes failed, because the many2one value wasn't correctly unset (`first record` was selected). This happened because we cleared…
Before this commit, the `empty a many2one field in list view` test sometimes failed, because the many2one value wasn't correctly unset (`first record` was selected). This happened because we cleared the input and automatically validated (typically with tab). However, it could happen that the validation occurred after the dropdown was opened, so the first value of the dropdown was selected. As a matter of fact, adding `await runAllTimers()` after clearing the input is a way to make the test fail deterministically. This commit avoids the issue by emptying the many2one without validation, so it basically only set the input value to the empty string, but doesn't tab/enter or anything else, hence it never selects an unwanted value. runbot error-941430 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#280351
**Steps to reproduce:** - Go to any view where you can send mails (eg sale orders) - Send a first mail to multiple recipients so they are added automatically on the next mail. - Open a new mail, confirm that the recipients are present, add a selectable attachment (eg a PDF), then click on it. - Remove any amount of recipients then send the mail. - You will see that the recipients are added back and the mail is sent to them. **Behavior:** Currently whenever a user clicks on an attachment
Original PR description
**Steps to reproduce:** - Go to any view where you can send mails (eg sale orders) - Send a first mail to multiple recipients so they are added automatically on the next mail. - Open a new mail,…
**Steps to reproduce:**
- Go to any view where you can send mails (eg sale orders)
- Send a first mail to multiple recipients so they are added automatically on the next mail.
- Open a new mail, confirm that the recipients are present, add a selectable attachment (eg a PDF), then click on it.
- Remove any amount of recipients then send the mail.
- You will see that the recipients are added back and the mail is sent to them.
**Behavior:**
Currently whenever a user clicks on an attachment in a mail composer, the systems considers that the user might be trying
to leave the page and will trigger an `urgentSave()`, and further down the line a `web_save()`.
The behavior when a web_save() is triggered is to create a record if there isnt currently one, and otherwise to write the modified values onto the record, using commands.
The recipients for the mail are added by default, which is represented by a list of `[4, id]`add commands, that will be written on the record created in the first `web_save`, however this list is not correctly emptied after the first `_save()`.
If the list is present within `this._changes` then it is correctly cleared, but in the case where no changes were made, the within `this._values['partner_ids']` still contains the commands.
So when we later assign `this.data = { ...this._values };`, `this.data['partner_ids']` now contains our uncleared list of commands.
https://github.com/odoo/odoo/blob/f3e407c6a58abd2ddba42f26fcbd1928da63cb63/addons/web/static/src/model/relational_model/record.js#L1222-L1230
And when we compute changes['partner_ids'] in our next iteration, we find ourselves with our command list again.
https://github.com/odoo/odoo/blob/f3e407c6a58abd2ddba42f26fcbd1928da63cb63/addons/web/static/src/model/relational_model/record.js#L1317-L1322
So when we then try to remove a recipient tag, the new delete command `[3, id]`
just gets canceled out with the already present add command.
And the `write()` in `web_save()` only writes add commands of already present partners, which doesn't do anything.
----
This commit adds a line to ensure commands inside `_values` are cleared
opw-6304713
Forward-Port-Of: odoo/odoo#280533
Forward-Port-Of: odoo/odoo#278876This is rather an attempt of fix, as we couldn't reproduce the error locally or in a multi build., so we have no guarantee that this strenghtens the test. The test sometimes fails as `.o_crop_icon` can't be found within 200ms. Before that, we wait for the video element to be ready (we rely on a patch of the `isVideoReady` method of the component to know that the video is ready). Once it is, the isReady flag in the state is set to true and the CropOverlay component renders its `o_crop_icon` el
Original PR description
This is rather an attempt of fix, as we couldn't reproduce the error locally or in a multi build., so we have no guarantee that this strenghtens the test. The test sometimes fails as `.o_crop_icon`…
This is rather an attempt of fix, as we couldn't reproduce the error locally or in a multi build., so we have no guarantee that this strenghtens the test. The test sometimes fails as `.o_crop_icon` can't be found within 200ms. Before that, we wait for the video element to be ready (we rely on a patch of the `isVideoReady` method of the component to know that the video is ready). Once it is, the isReady flag in the state is set to true and the CropOverlay component renders its `o_crop_icon` element. Our guess is that we may sometimes early return in `isVideoReady`, because the component has been destroyed (a new rendering might be on the way). To ensure that we don't take that as the ready signal in the test, we now only consider that we're ready if isVideoReady returned true (i.e. no early return). runbot error-241798 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#280329
When a customer invoice is digitized through OCR, the salesperson may be set to the "Public User" instead of the internal user who uploaded the document. Steps to reproduce: - Upload a PDF invoice of an existing customer - Send the PDF to OCR - Reload the page Issue: Observe the Salesperson field: it is set to the Public User. Analysis: This occurs because when the partner is filled in, the compute of the salesperson will trigger. On SaaS this happens through the extraction c
Original PR description
When a customer invoice is digitized through OCR, the salesperson may be set to the "Public User" instead of the internal user who uploaded the document. Steps to reproduce: - Upload a PDF invoice of an existing customer - Send the PDF to OCR - Reload the page Issue: Observe the Salesperson field: it is set to the Public User. Analysis: This occurs because when the partner is filled in, the compute of the salesperson will trigger. On SaaS this happens through the extraction completion webhook a public route processed in sudo. that does not change the current user (public user). As self.env.user is the fallback of the compute, it may be set as salesperson. opw-6296330 Forward-Port-Of: odoo/odoo#279724
**Issue** Confirming a SO that generates a batch of MOs from a BoM with a batch size could lead to creating an invalid number of pickings: all the MOs end up sharing a single picking instead of getting one each. **Steps to reproduce** - Use 2-step manufacturing - Create a storable product with the MTO + Manufacture routes - Add a BOM that has a batch size of 10 that consumes one component - Create and confirm a SO of 100 units of that product -> 10 MOs are created, but each one points
Original PR description
**Issue** Confirming a SO that generates a batch of MOs from a BoM with a batch size could lead to creating an invalid number of pickings: all the MOs end up sharing a single picking instead of…
**Issue** Confirming a SO that generates a batch of MOs from a BoM with a batch size could lead to creating an invalid number of pickings: all the MOs end up sharing a single picking instead of getting one each. **Steps to reproduce** - Use 2-step manufacturing - Create a storable product with the MTO + Manufacture routes - Add a BOM that has a batch size of 10 that consumes one component - Create and confirm a SO of 100 units of that product -> 10 MOs are created, but each one points to the same "Pick Components" transfer instead of getting its own. **Cause** This commit dd6ee071f949752d31497d9f975ba7fc41ebcd98 batches the confirm of productions: https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/mrp/models/stock_rule.py#L120 thus `assign_picking` is called in batches: https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/mrp/models/mrp_production.py#L1653 https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1736-L1737 https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1550-L1556 since, the `reference_ids` are the same for each MO/stock.move (they all come from the same procurement): https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1712-L1713 Consequently, all the moves end up in the same recordset `moves`: https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1527 Creating only one picking: https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1577 opw-6403427 Forward-Port-Of: odoo/odoo#279179
Issue ----- Branch companies can have quants of a product limited to their parent company, but they don't show in the per location report. Steps to reproduce ----- - Create a branch company - Create a WH for the branch - Create a tracked product - Company set to parent only - Switch to the branch company - Add a quant of the product in branch stock - Open Inventory > Reporting > Locations > The product is not shown although there is a quant in the branch Cause ----- The m
Original PR description
Issue ----- Branch companies can have quants of a product limited to their parent company, but they don't show in the per location report. Steps to reproduce ----- - Create a branch company - Create…
Issue ----- Branch companies can have quants of a product limited to their parent company, but they don't show in the per location report. Steps to reproduce ----- - Create a branch company - Create a WH for the branch - Create a tracked product - Company set to parent only - Switch to the branch company - Add a quant of the product in branch stock - Open Inventory > Reporting > Locations > The product is not shown although there is a quant in the branch Cause ----- The menu button triggers `action_view_quants` https://github.com/odoo/odoo/blob/03a3662212f094158f885ae6545009fd0a74d3cb/addons/stock/views/stock_quant_views.xml#L493-L495 https://github.com/odoo/odoo/blob/03a3662212f094158f885ae6545009fd0a74d3cb/addons/stock/models/stock_quant.py#L399-L402 The problem here comes from the fact that in `_get_quants_action`, we limit the products to those of only the active companies, instead of allowing to view those of parent companies aswell. https://github.com/odoo/odoo/blob/03a3662212f094158f885ae6545009fd0a74d3cb/addons/stock/models/stock_quant.py#L1330 Such a change works because the domain is specifically for the product's (`product_id.company_id`) and not the location's. ----- Ticket: opw-6131525 Forward-Port-Of: odoo/odoo#280083 Forward-Port-Of: odoo/odoo#277531
Version: -------- - 19.0+ Steps to reproduce: ------------------- - Install `purchase` and `stock` - Create a Purchase Order for a storable or consumable product - Set the ordered quantity to a negative value (e.g. `-10`) - Confirm the Purchase Order. - Open the Deliveries and search using the Purchase Order name Issue: ------ An outgoing return picking is correctly created for 10 units, but an additional empty incoming receipt is also generated and linked to the Purchase Order
Original PR description
Version: -------- - 19.0+ Steps to reproduce: ------------------- - Install `purchase` and `stock` - Create a Purchase Order for a storable or consumable product - Set the ordered quantity to a…
Version: -------- - 19.0+ Steps to reproduce: ------------------- - Install `purchase` and `stock` - Create a Purchase Order for a storable or consumable product - Set the ordered quantity to a negative value (e.g. `-10`) - Confirm the Purchase Order. - Open the Deliveries and search using the Purchase Order name Issue: ------ An outgoing return picking is correctly created for 10 units, but an additional empty incoming receipt is also generated and linked to the Purchase Order. Cause: ------ When a Purchase Order is confirmed, `purchase.order.button_approve()` calls `purchase.order._create_picking()`: https://github.com/odoo/odoo/blob/ed0d1bd21131920cb9c7b2ae69d7baedc2818e85/addons/purchase_stock/models/purchase_order.py#L179 Inside `_create_picking()`, if no open picking exists yet, Then first creates an incoming receipt using `_prepare_picking()`: https://github.com/odoo/odoo/blob/ed0d1bd21131920cb9c7b2ae69d7baedc2818e85/addons/purchase_stock/models/purchase_order.py#L382 The generated receipt is configured with: - source location: Vendor - destination location: Stock - picking type: Incoming - origin: Purchase Order reference Stock moves are then created on that receipt through: https://github.com/odoo/odoo/blob/ed0d1bd21131920cb9c7b2ae69d7baedc2818e85/addons/purchase_stock/models/purchase_order.py#L387-L388 For negative PO quantities, the move is initially created with a negative demand: ``` Vendor -> Stock, quantity -10 ```` During `stock.move._action_confirm()`, stock identifies such moves in `neg_r_moves`: [https://github.com/odoo/odoo/blob/ed0d1bd21131920cb9c7b2ae69d7baedc2818e85/addons/stock/models/stock_move.py#L1604](https://github.com/odoo/odoo/blob/ed0d1bd21131920cb9c7b2ae69d7baedc2818e85/addons/stock/models/stock_move.py#L1604) Those moves are automatically converted into return moves by: * swapping source and destination locations, * converting the quantity to positive, * assigning the return picking type when available: [https://github.com/odoo/odoo/blob/ed0d1bd21131920cb9c7b2ae69d7baedc2818e85/addons/stock/models/stock_move.py#L1612-L1614](https://github.com/odoo/odoo/blob/ed0d1bd21131920cb9c7b2ae69d7baedc2818e85/addons/stock/models/stock_move.py#L1612-L1614) The resulting move becomes: ``` Stock -> Vendor, quantity 10 ``` The converted move is then reassigned through: [https://github.com/odoo/odoo/blob/ed0d1bd21131920cb9c7b2ae69d7baedc2818e85/addons/stock/models/stock_move.py#L1630](https://github.com/odoo/odoo/blob/ed0d1bd21131920cb9c7b2ae69d7baedc2818e85/addons/stock/models/stock_move.py#L1630) This correctly creates the outgoing return picking. However, the original incoming receipt created earlier by `purchase_stock` is left without any moves, resulting in an empty ghost receipt linked to the Purchase Order. Solution: --------- - Track whether `_create_picking()` created a new incoming receipt during the current confirmation flow. - After stock move confirmation, if that newly-created receipt no longer contains any moves, unlink it and remove it from the pickings to confirm. - This preserves the valid outgoing return picking while preventing empty incoming receipts from being generated. NOTE: ------ This Issue not reproduce from saas-19.3. Fix in this [commit](https://github.com/odoo-dev/odoo/commit/81caaaa3f7212ad5d9d72cd446b65c5fb0a9bef9) --- opw-6131329 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#265704
### Steps to reproduce: - Create 3 AVCO products: Super Kit, Kit, Comp - Super Kit BoM: 2 x Kit - Kit BoM: 1 x Comp - Create and confirm a purchase order for 1 X Super Kit at 100 - Validate the receipt of 2 Comp - Go to the valuation > Both units of Comp are valued at 100 for a total of 200 ### Cause of the issue: The issue has been introduced by: https://github.com/odoo/odoo/pull/158849/changes/713701a5035d342263e3fef2a2819b5696b6d063 To be more precise, the price unit of each u
Original PR description
### Steps to reproduce: - Create 3 AVCO products: Super Kit, Kit, Comp - Super Kit BoM: 2 x Kit - Kit BoM: 1 x Comp - Create and confirm a purchase order for 1 X Super Kit at 100 - Validate the…
### Steps to reproduce: - Create 3 AVCO products: Super Kit, Kit, Comp - Super Kit BoM: 2 x Kit - Kit BoM: 1 x Comp - Create and confirm a purchase order for 1 X Super Kit at 100 - Validate the receipt of 2 Comp - Go to the valuation > Both units of Comp are valued at 100 for a total of 200 ### Cause of the issue: The issue has been introduced by: https://github.com/odoo/odoo/pull/158849/changes/713701a5035d342263e3fef2a2819b5696b6d063 To be more precise, the price unit of each unit of Comp is expected to be computed by the `_get_price_unit`. This method used to rely on the `product_qty` appropriately: https://github.com/odoo/odoo/pull/158849/changes/713701a5035d342263e3fef2a2819b5696b6d063#diff-687527af1723e60816358020c4d83687479df62ca0cfd71079f0a82afb4b3efeL27 However, backorder adapt the move demand and hence did not provide the appropriate demand in this flow that computation logic was changed to rely on the `bom` and `bom_line` quantities: https://github.com/odoo/odoo/blob/29977a6a80442af49ecefa7fef54f085483d8f77/addons/purchase_mrp/models/stock_move.py#L20-L40 This new computation is not correct in case of nested boms since the `bom_line` only carries the unit demand on the last explosion stage. ### Additional issue: If nested kit boms lead to the creation of 2 moves with the same `cost_share` and `bom_line_id`, these moves will be merged without summing their `cost_share` leading to an under pricing of the kit since its related `stock_move`'s `cost_share` will not sum up to 100 percents anymore. This issue is tested in `test_avco_purchase_nested_kit_explode_cost_share_backorder_2` and fixed similarly to demand merging: https://github.com/odoo/odoo/blob/613f3cb7b2f4813ce6c8f53718a6cca841b081ad/addons/stock/models/stock_move.py#L1122-L1134 ### Note: We also modify the test `test_valuation_with_backorder` to be understandable and to make appropriate asserts. opw-6253776 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279890 Forward-Port-Of: odoo/odoo#276242
Steps to reproduce the bug: - Create three storable products C1 ($10), C2 ($20), C3 ($5) - Create a product P1 with a BoM: 1x C1 + 1x C2 - Create a Manufacturing Order for P1 and validate it - Unlock the MO (Settings > Unlock) - Add C3 as an extra component on the unlocked MO - Open the MO overview Problem: The extra move had value=0 after creation, causing the unit_cost in the MO overview to appear as 0. When a move is added to a done picking or MO it is created with state='done' an
Original PR description
Steps to reproduce the bug: - Create three storable products C1 ($10), C2 ($20), C3 ($5) - Create a product P1 with a BoM: 1x C1 + 1x C2 - Create a Manufacturing Order for P1 and validate it - Unlock…
Steps to reproduce the bug: - Create three storable products C1 ($10), C2 ($20), C3 ($5) - Create a product P1 with a BoM: 1x C1 + 1x C2 - Create a Manufacturing Order for P1 and validate it - Unlock the MO (Settings > Unlock) - Add C3 as an extra component on the unlocked MO - Open the MO overview Problem: The extra move had value=0 after creation, causing the unit_cost in the MO overview to appear as 0. When a move is added to a done picking or MO it is created with state='done' and quantity set immediately. This triggers _set_quantity_done, which creates the move line and calls _set_value(correction_quantity=delta). Inside _set_value, for outgoing moves with a correction_quantity, the code computes: previous_qty = move.quantity - correction_quantity Since the move had no prior quantity, previous_qty=0. The original code then computed ratio=0 and applied move.value += 0, leaving value=0 instead of computing it from scratch. Solution: When previous_qty=0, skip the ratio branch and fall through to the existing from-scratch computation (standard_price * _get_valued_qty() for AVCO/standard costing, _run_fifo() for FIFO). opw-6377393 Forward-Port-Of: odoo/odoo#276303
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 Forward-Port-Of: odoo/odoo#280162 Forward-Port-Of: odoo/odoo#254090
19 changes
Enhancements to existing features
The decorator `no_retry` can be used on any objects and just sets a flag. When checking if we should retry a test, let's also check the value on the class. This was broken by 2423b460526e9e7dd9ea8a7b3f7e40c93ab708f5. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280641
Original PR description
The decorator `no_retry` can be used on any objects and just sets a flag. When checking if we should retry a test, let's also check the value on the class. This was broken by 2423b460526e9e7dd9ea8a7b3f7e40c93ab708f5. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280641
This commit adds 3 new `Tax Exemption Reason Code`: - VATEX-FR-F - VATEX-FR-I - VATEX-FR-J task-6333649 Forward-Port-Of: odoo/odoo#280537 Forward-Port-Of: odoo/odoo#278086
Original PR description
This commit adds 3 new `Tax Exemption Reason Code`: - VATEX-FR-F - VATEX-FR-I - VATEX-FR-J task-6333649 Forward-Port-Of: odoo/odoo#280537 Forward-Port-Of: odoo/odoo#278086
Resolved issues and error corrections
Version: -------- - 19.0+ Steps to reproduce: ------------------- - Install `purchase` and `stock` - Create a Purchase Order for a storable or consumable product - Set the ordered quantity to a negative value (e.g. `-10`) - Confirm the Purchase Order. - Open the Deliveries and search using the Purchase Order name Issue: ------ An outgoing return picking is correctly created for 10 units, but an additional empty incoming receipt is also generated and linked to the Purchase Order
Original PR description
Version: -------- - 19.0+ Steps to reproduce: ------------------- - Install `purchase` and `stock` - Create a Purchase Order for a storable or consumable product - Set the ordered quantity to a…
Version: -------- - 19.0+ Steps to reproduce: ------------------- - Install `purchase` and `stock` - Create a Purchase Order for a storable or consumable product - Set the ordered quantity to a negative value (e.g. `-10`) - Confirm the Purchase Order. - Open the Deliveries and search using the Purchase Order name Issue: ------ An outgoing return picking is correctly created for 10 units, but an additional empty incoming receipt is also generated and linked to the Purchase Order. Cause: ------ When a Purchase Order is confirmed, `purchase.order.button_approve()` calls `purchase.order._create_picking()`: https://github.com/odoo/odoo/blob/ed0d1bd21131920cb9c7b2ae69d7baedc2818e85/addons/purchase_stock/models/purchase_order.py#L179 Inside `_create_picking()`, if no open picking exists yet, Then first creates an incoming receipt using `_prepare_picking()`: https://github.com/odoo/odoo/blob/ed0d1bd21131920cb9c7b2ae69d7baedc2818e85/addons/purchase_stock/models/purchase_order.py#L382 The generated receipt is configured with: - source location: Vendor - destination location: Stock - picking type: Incoming - origin: Purchase Order reference Stock moves are then created on that receipt through: https://github.com/odoo/odoo/blob/ed0d1bd21131920cb9c7b2ae69d7baedc2818e85/addons/purchase_stock/models/purchase_order.py#L387-L388 For negative PO quantities, the move is initially created with a negative demand: ``` Vendor -> Stock, quantity -10 ```` During `stock.move._action_confirm()`, stock identifies such moves in `neg_r_moves`: [https://github.com/odoo/odoo/blob/ed0d1bd21131920cb9c7b2ae69d7baedc2818e85/addons/stock/models/stock_move.py#L1604](https://github.com/odoo/odoo/blob/ed0d1bd21131920cb9c7b2ae69d7baedc2818e85/addons/stock/models/stock_move.py#L1604) Those moves are automatically converted into return moves by: * swapping source and destination locations, * converting the quantity to positive, * assigning the return picking type when available: [https://github.com/odoo/odoo/blob/ed0d1bd21131920cb9c7b2ae69d7baedc2818e85/addons/stock/models/stock_move.py#L1612-L1614](https://github.com/odoo/odoo/blob/ed0d1bd21131920cb9c7b2ae69d7baedc2818e85/addons/stock/models/stock_move.py#L1612-L1614) The resulting move becomes: ``` Stock -> Vendor, quantity 10 ``` The converted move is then reassigned through: [https://github.com/odoo/odoo/blob/ed0d1bd21131920cb9c7b2ae69d7baedc2818e85/addons/stock/models/stock_move.py#L1630](https://github.com/odoo/odoo/blob/ed0d1bd21131920cb9c7b2ae69d7baedc2818e85/addons/stock/models/stock_move.py#L1630) This correctly creates the outgoing return picking. However, the original incoming receipt created earlier by `purchase_stock` is left without any moves, resulting in an empty ghost receipt linked to the Purchase Order. Solution: --------- - Track whether `_create_picking()` created a new incoming receipt during the current confirmation flow. - After stock move confirmation, if that newly-created receipt no longer contains any moves, unlink it and remove it from the pickings to confirm. - This preserves the valid outgoing return picking while preventing empty incoming receipts from being generated. NOTE: ------ This Issue not reproduce from saas-19.3. Fix in this [commit](https://github.com/odoo-dev/odoo/commit/81caaaa3f7212ad5d9d72cd446b65c5fb0a9bef9) --- opw-6131329 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#265704
Before this commit: Deleting a record that uses a filterable selection field with `whitelist_fname` raises a traceback because the record field data becomes undefined during deletion. Steps to reproduce: 1. Install Belgium Accounting (l10n_be). 2. Create a contact and set a Peppol scheme and endpoint. 3. Delete the contact -> a traceback is raised. After this commit: The selection field safely handles undefined record field data during record deletion without causing an error. no-t
Original PR description
Before this commit: Deleting a record that uses a filterable selection field with `whitelist_fname` raises a traceback because the record field data becomes undefined during deletion. Steps to reproduce: 1. Install Belgium Accounting (l10n_be). 2. Create a contact and set a Peppol scheme and endpoint. 3. Delete the contact -> a traceback is raised. After this commit: The selection field safely handles undefined record field data during record deletion without causing an error. no-task Forward-Port-Of: odoo/odoo#280153 Forward-Port-Of: odoo/odoo#278808
### Issue: A user who can modify `tax_exigibility` but does not have `account.group_account_readonly` is blocked from switching to `on_payment` There is no way to complete the operation as the account field is not visible and cannot be filled before saving ### Cause: When `tax_exigibility` is set to `on_payment`, the view expects `cash_basis_transition_account_id` to be filled before saving`_constrains_cash_basis_transition_account` then validates that the account is reconcilable `cas
Original PR description
### Issue: A user who can modify `tax_exigibility` but does not have `account.group_account_readonly` is blocked from switching to `on_payment` There is no way to complete the operation as the…
### Issue: A user who can modify `tax_exigibility` but does not have `account.group_account_readonly` is blocked from switching to `on_payment` There is no way to complete the operation as the account field is not visible and cannot be filled before saving ### Cause: When `tax_exigibility` is set to `on_payment`, the view expects `cash_basis_transition_account_id` to be filled before saving`_constrains_cash_basis_transition_account` then validates that the account is reconcilable `cash_basis_transition_account_id` was restricted to `account.group_account_readonly`, hiding it from other users The field is never rendered, so it cannot be filled The `required` constraint is never evaluated client-side and `_constrains_cash_basis_transition_account` raises a `ValidationError` on save because the account is empty There is no reason to restrict `cash_basis_transition_account_id` independently — if a user can modify `tax_exigibility`, they must also be able to set the linked account ### Steps to reproduce: - Install `account` - Enable Cash Basis in Settings (On RunBot ensure no default account is set) - Enable Developer Mode in Settings - Go to Settings > Users & Companies > Users - Open the current user and disable both: `Show Accounting Features - Readonly` and `Show Full Accounting Features` (if set) - Go to Invoicing > Configuration > Taxes - Open any tax and go to Advanced Options - Change Tax Exigibility to Based on Payment Before the fix, the account selector is not displayed and saving raises an error opw-6359173 Forward-Port-Of: odoo/odoo#274728
Since https://github.com/odoo/odoo/pull/239898 Opening a livechat session in debug mode as a user without livechat access throws a traceback: `Invalid props for component BadgeTag: onDelete is not a function` This happens because `null` is passed to the `onDelete` prop, while the component validation expects a function. This commit fixes the issue. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
Since https://github.com/odoo/odoo/pull/239898 Opening a livechat session in debug mode as a user without livechat access throws a traceback: `Invalid props for component BadgeTag: onDelete is not a function` This happens because `null` is passed to the `onDelete` prop, while the component validation expects a function. This commit fixes the issue. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Before this commit, the `empty a many2one field in list view` test sometimes failed, because the many2one value wasn't correctly unset (`first record` was selected). This happened because we cleared the input and automatically validated (typically with tab). However, it could happen that the validation occurred after the dropdown was opened, so the first value of the dropdown was selected. As a matter of fact, adding `await runAllTimers()` after clearing the input is a way to make the test fail
Original PR description
Before this commit, the `empty a many2one field in list view` test sometimes failed, because the many2one value wasn't correctly unset (`first record` was selected). This happened because we cleared…
Before this commit, the `empty a many2one field in list view` test sometimes failed, because the many2one value wasn't correctly unset (`first record` was selected). This happened because we cleared the input and automatically validated (typically with tab). However, it could happen that the validation occurred after the dropdown was opened, so the first value of the dropdown was selected. As a matter of fact, adding `await runAllTimers()` after clearing the input is a way to make the test fail deterministically. This commit avoids the issue by emptying the many2one without validation, so it basically only set the input value to the empty string, but doesn't tab/enter or anything else, hence it never selects an unwanted value. runbot error-941430 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#280351
This is rather an attempt of fix, as we couldn't reproduce the error locally or in a multi build., so we have no guarantee that this strenghtens the test. The test sometimes fails as `.o_crop_icon` can't be found within 200ms. Before that, we wait for the video element to be ready (we rely on a patch of the `isVideoReady` method of the component to know that the video is ready). Once it is, the isReady flag in the state is set to true and the CropOverlay component renders its `o_crop_icon` el
Original PR description
This is rather an attempt of fix, as we couldn't reproduce the error locally or in a multi build., so we have no guarantee that this strenghtens the test. The test sometimes fails as `.o_crop_icon`…
This is rather an attempt of fix, as we couldn't reproduce the error locally or in a multi build., so we have no guarantee that this strenghtens the test. The test sometimes fails as `.o_crop_icon` can't be found within 200ms. Before that, we wait for the video element to be ready (we rely on a patch of the `isVideoReady` method of the component to know that the video is ready). Once it is, the isReady flag in the state is set to true and the CropOverlay component renders its `o_crop_icon` element. Our guess is that we may sometimes early return in `isVideoReady`, because the component has been destroyed (a new rendering might be on the way). To ensure that we don't take that as the ready signal in the test, we now only consider that we're ready if isVideoReady returned true (i.e. no early return). runbot error-241798 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#280329
When a customer invoice is digitized through OCR, the salesperson may be set to the "Public User" instead of the internal user who uploaded the document. Steps to reproduce: - Upload a PDF invoice of an existing customer - Send the PDF to OCR - Reload the page Issue: Observe the Salesperson field: it is set to the Public User. Analysis: This occurs because when the partner is filled in, the compute of the salesperson will trigger. On SaaS this happens through the extraction c
Original PR description
When a customer invoice is digitized through OCR, the salesperson may be set to the "Public User" instead of the internal user who uploaded the document. Steps to reproduce: - Upload a PDF invoice of an existing customer - Send the PDF to OCR - Reload the page Issue: Observe the Salesperson field: it is set to the Public User. Analysis: This occurs because when the partner is filled in, the compute of the salesperson will trigger. On SaaS this happens through the extraction completion webhook a public route processed in sudo. that does not change the current user (public user). As self.env.user is the fallback of the compute, it may be set as salesperson. opw-6296330 Forward-Port-Of: odoo/odoo#279724
### Steps to reproduce: - Create 3 AVCO products: Super Kit, Kit, Comp - Super Kit BoM: 2 x Kit - Kit BoM: 1 x Comp - Create and confirm a purchase order for 1 X Super Kit at 100 - Validate the receipt of 2 Comp - Go to the valuation > Both units of Comp are valued at 100 for a total of 200 ### Cause of the issue: The issue has been introduced by: https://github.com/odoo/odoo/pull/158849/changes/713701a5035d342263e3fef2a2819b5696b6d063 To be more precise, the price unit of each u
Original PR description
### Steps to reproduce: - Create 3 AVCO products: Super Kit, Kit, Comp - Super Kit BoM: 2 x Kit - Kit BoM: 1 x Comp - Create and confirm a purchase order for 1 X Super Kit at 100 - Validate the…
### Steps to reproduce: - Create 3 AVCO products: Super Kit, Kit, Comp - Super Kit BoM: 2 x Kit - Kit BoM: 1 x Comp - Create and confirm a purchase order for 1 X Super Kit at 100 - Validate the receipt of 2 Comp - Go to the valuation > Both units of Comp are valued at 100 for a total of 200 ### Cause of the issue: The issue has been introduced by: https://github.com/odoo/odoo/pull/158849/changes/713701a5035d342263e3fef2a2819b5696b6d063 To be more precise, the price unit of each unit of Comp is expected to be computed by the `_get_price_unit`. This method used to rely on the `product_qty` appropriately: https://github.com/odoo/odoo/pull/158849/changes/713701a5035d342263e3fef2a2819b5696b6d063#diff-687527af1723e60816358020c4d83687479df62ca0cfd71079f0a82afb4b3efeL27 However, backorder adapt the move demand and hence did not provide the appropriate demand in this flow that computation logic was changed to rely on the `bom` and `bom_line` quantities: https://github.com/odoo/odoo/blob/29977a6a80442af49ecefa7fef54f085483d8f77/addons/purchase_mrp/models/stock_move.py#L20-L40 This new computation is not correct in case of nested boms since the `bom_line` only carries the unit demand on the last explosion stage. ### Additional issue: If nested kit boms lead to the creation of 2 moves with the same `cost_share` and `bom_line_id`, these moves will be merged without summing their `cost_share` leading to an under pricing of the kit since its related `stock_move`'s `cost_share` will not sum up to 100 percents anymore. This issue is tested in `test_avco_purchase_nested_kit_explode_cost_share_backorder_2` and fixed similarly to demand merging: https://github.com/odoo/odoo/blob/613f3cb7b2f4813ce6c8f53718a6cca841b081ad/addons/stock/models/stock_move.py#L1122-L1134 ### Note: We also modify the test `test_valuation_with_backorder` to be understandable and to make appropriate asserts. opw-6253776 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279890 Forward-Port-Of: odoo/odoo#276242
**Issue** Confirming a SO that generates a batch of MOs from a BoM with a batch size could lead to creating an invalid number of pickings: all the MOs end up sharing a single picking instead of getting one each. **Steps to reproduce** - Use 2-step manufacturing - Create a storable product with the MTO + Manufacture routes - Add a BOM that has a batch size of 10 that consumes one component - Create and confirm a SO of 100 units of that product -> 10 MOs are created, but each one points
Original PR description
**Issue** Confirming a SO that generates a batch of MOs from a BoM with a batch size could lead to creating an invalid number of pickings: all the MOs end up sharing a single picking instead of…
**Issue** Confirming a SO that generates a batch of MOs from a BoM with a batch size could lead to creating an invalid number of pickings: all the MOs end up sharing a single picking instead of getting one each. **Steps to reproduce** - Use 2-step manufacturing - Create a storable product with the MTO + Manufacture routes - Add a BOM that has a batch size of 10 that consumes one component - Create and confirm a SO of 100 units of that product -> 10 MOs are created, but each one points to the same "Pick Components" transfer instead of getting its own. **Cause** This commit dd6ee071f949752d31497d9f975ba7fc41ebcd98 batches the confirm of productions: https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/mrp/models/stock_rule.py#L120 thus `assign_picking` is called in batches: https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/mrp/models/mrp_production.py#L1653 https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1736-L1737 https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1550-L1556 since, the `reference_ids` are the same for each MO/stock.move (they all come from the same procurement): https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1712-L1713 Consequently, all the moves end up in the same recordset `moves`: https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1527 Creating only one picking: https://github.com/odoo/odoo/blob/b51dc298fd63d9586d0b8d7cff59764b0dee5cae/addons/stock/models/stock_move.py#L1577 opw-6403427 Forward-Port-Of: odoo/odoo#279179
Issue ----- Branch companies can have quants of a product limited to their parent company, but they don't show in the per location report. Steps to reproduce ----- - Create a branch company - Create a WH for the branch - Create a tracked product - Company set to parent only - Switch to the branch company - Add a quant of the product in branch stock - Open Inventory > Reporting > Locations > The product is not shown although there is a quant in the branch Cause ----- The m
Original PR description
Issue ----- Branch companies can have quants of a product limited to their parent company, but they don't show in the per location report. Steps to reproduce ----- - Create a branch company - Create…
Issue ----- Branch companies can have quants of a product limited to their parent company, but they don't show in the per location report. Steps to reproduce ----- - Create a branch company - Create a WH for the branch - Create a tracked product - Company set to parent only - Switch to the branch company - Add a quant of the product in branch stock - Open Inventory > Reporting > Locations > The product is not shown although there is a quant in the branch Cause ----- The menu button triggers `action_view_quants` https://github.com/odoo/odoo/blob/03a3662212f094158f885ae6545009fd0a74d3cb/addons/stock/views/stock_quant_views.xml#L493-L495 https://github.com/odoo/odoo/blob/03a3662212f094158f885ae6545009fd0a74d3cb/addons/stock/models/stock_quant.py#L399-L402 The problem here comes from the fact that in `_get_quants_action`, we limit the products to those of only the active companies, instead of allowing to view those of parent companies aswell. https://github.com/odoo/odoo/blob/03a3662212f094158f885ae6545009fd0a74d3cb/addons/stock/models/stock_quant.py#L1330 Such a change works because the domain is specifically for the product's (`product_id.company_id`) and not the location's. ----- Ticket: opw-6131525 Forward-Port-Of: odoo/odoo#280083 Forward-Port-Of: odoo/odoo#277531
Task-6429727 Forward-Port-Of: odoo/odoo#279204
Original PR description
Task-6429727 Forward-Port-Of: odoo/odoo#279204
Steps to reproduce the error: (Python Version: 3.14.X) - Install ``accounting_firm`` industry with demo data Code for server action to generate the error: ```py for i in [1]: try: pass except Exception: pass if i: pass ``` Traceback: ```py ValueError: forbidden opcode(s) in'...': JUMP_BACKWARD_NO_INTERRUPT ``` https://github.com/odoo/industry/blob/701f7595453772e42ce72aa75df346a504e5bd82/accounting_firm/demo/ir_actions_server.xml#L105-L10
Original PR description
Steps to reproduce the error: (Python Version: 3.14.X) - Install ``accounting_firm`` industry with demo data Code for server action to generate the error: ```py for i in [1]: try: pass except…
Steps to reproduce the error: (Python Version: 3.14.X)
- Install ``accounting_firm`` industry with demo data
Code for server action to generate the error:
```py
for i in [1]:
try:
pass
except Exception:
pass
if i:
pass
```
Traceback:
```py
ValueError: forbidden opcode(s) in'...': JUMP_BACKWARD_NO_INTERRUPT
```
https://github.com/odoo/industry/blob/701f7595453772e42ce72aa75df346a504e5bd82/accounting_firm/demo/ir_actions_server.xml#L105-L108
The server action contains a ``for`` loop with a ``try/except`` block followed by additional statements in the loop body,
this combination generates the ``JUMP_BACKWARD_NO_INTERRUPT`` opcode, which is not included in ``_SAFE_OPCODES`` at [1].
When the server action is evaluated by ``safe_eval``, it calls the ``assert_valid_codeobj`` method, which validates the compiled bytecode against ``_SAFE_OPCODES``. Since ``JUMP_BACKWARD_NO_INTERRUPT`` is not present in the allowed opcodes, ``assert_valid_codeobj()`` raises a ``ValueError`` at [2] before the server action is executed .
Solution:
``JUMP_BACKWARD_NO_INTERRUPT`` opcode is added in the ``_SAFE_OPCODES`` and it is also added in the ``_SAFE_QWEB_OPCODES``.
It was added in Python 3.11: https://docs.python.org/3/whatsnew/3.11.html#new-opcodes
``JUMP_BACKWARD_NO_INTERRUPT`` is a control-flow opcode that only changes
the interpreter's execution flow by jumping back to a previous instruction.
It is the equivalent to ``JUMP_BACKWARD`` opcode. Its only semantic difference is
that the interpreter does not perform an interrupt check at that instruction.
It does not introduce any new capabilities or perform operations such as
attribute access, imports, function calls, or object creation.
Ref: https://docs.python.org/3.12/library/dis.html#opcode-JUMP_BACKWARD_NO_INTERRUPT
Similar commit that adds some necessary opcodes:
https://github.com/odoo/odoo/commit/86498d24946e510025add5d24ef0d4bcce8ad05f
[1]: https://github.com/odoo/odoo/blob/2ccbc4660077bd48529e9de43d4309fbfafc75ca/odoo/tools/safe_eval.py#L135
[2]: https://github.com/odoo/odoo/blob/2ccbc4660077bd48529e9de43d4309fbfafc75ca/odoo/tools/safe_eval.py#L244-L246
sentry-7614026125
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#277192### Issue: A partner with VAT set to '/' incorrectly matches a fiscal position with `VAT required`, instead of one without The '/' value is the placeholder suggested by the UI to indicate that the partner is known to have no VAT, but it was treated as a valid VAT by the fiscal position matching logic ### Cause: `_get_fpos_ranking_functions` uses `_get_vat_valid` to rank fiscal positions based on VAT presence `_get_vat_valid` returned `True` for any non-empty VAT value, including '/' Th
Original PR description
### Issue: A partner with VAT set to '/' incorrectly matches a fiscal position with `VAT required`, instead of one without The '/' value is the placeholder suggested by the UI to indicate that the…
### Issue: A partner with VAT set to '/' incorrectly matches a fiscal position with `VAT required`, instead of one without The '/' value is the placeholder suggested by the UI to indicate that the partner is known to have no VAT, but it was treated as a valid VAT by the fiscal position matching logic ### Cause: `_get_fpos_ranking_functions` uses `_get_vat_valid` to rank fiscal positions based on VAT presence `_get_vat_valid` returned `True` for any non-empty VAT value, including '/' The '/' case was not excluded, causing it to be treated as a valid VAT number ### Steps to reproduce: - Install `account` - Create two fiscal positions with auto-apply: -- Name: FP VAT, VAT required: True, sequence: 1 -- Name: FP no VAT, VAT required: False, sequence: 2 - Create a partner with VAT: '/' - Create an Invoice for that partner and check the Fiscal Position Before the fix, `FP VAT` is selected instead of `FP no VAT` opw-6204531 Forward-Port-Of: odoo/odoo#280494 Forward-Port-Of: odoo/odoo#280065
## Issue When logging timesheet from the *Recorded* smart button on a Sale Order containing multiple service items, the recorded hours will be added to the first sale order line, regardless of the task ID set on the timesheet entries. ## Steps to reproduce 1. Install *Sales Timesheet* (`sale_timesheet`) 2. Create a Product P: - *Product Type*: Service - *Create on Order*: Task - *Project*: Any 3. Create a SO: - *Customer*: Any - Add the product P on two different
Original PR description
## Issue When logging timesheet from the *Recorded* smart button on a Sale Order containing multiple service items, the recorded hours will be added to the first sale order line, regardless of the…
## Issue
When logging timesheet from the *Recorded* smart button on a Sale Order containing multiple service items, the recorded hours will be added to the first sale order line, regardless of the task ID set on the timesheet entries.
## Steps to reproduce
1. Install *Sales Timesheet* (`sale_timesheet`)
2. Create a Product P:
- *Product Type*: Service
- *Create on Order*: Task
- *Project*: Any
3. Create a SO:
- *Customer*: Any
- Add the product P on two different lines and give them two different descriptions D1 and D2
- Confirm the SO, this will create two tasks with the names D1 and D2
4. On the SO, click the *Recorded* smart button and create two entries:
1. Task D1, 2 hours spent
2. Tsk D2, 3 hours spent
5. **Back on the SO, there are 5 hours registered for the first SOL (with the description D1), which does not match the entries we created from the smart button.**
It is worth noting that when we create the Timesheets entries from the project itself (instead of the SO's smart button), the hours are correctly distributed among the different SOLs.
## Cause
The SOL linked to the timesheet entry (`account.analytic.line`) is computed by `_compute_so_line`:
https://github.com/odoo/odoo/blob/8b102f500f5a122e99b07a08cc43814e7c6f0f75/addons/sale_timesheet/models/hr_timesheet.py#L79-L82
This method sets the correct SOL under the condition that `is_so_line_edited` is False and `_is_no_billed()` returns True.
When opening the *Recorded* smart button from a SO, the `is_so_line_edited` is set to True by default, even if no SOL was modified.
https://github.com/odoo/odoo/blob/8b102f500f5a122e99b07a08cc43814e7c6f0f75/addons/sale_timesheet/models/sale_order.py#L113-L117
As that value is never set to False, when trying to compute the SOL for the timesheet entry, the entry is skipped and the default SOL (which is the first one) is used instead.
opw-6133473
Forward-Port-Of: odoo/odoo#274759Before this commit, in some cases, the order created for printing cash move was saved to the IndexedDB and then later loaded from IndexedDB, which caused the order gets synced to the backend but missing some required fields, like preset or pricelist. opw-5969602 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262248
Original PR description
Before this commit, in some cases, the order created for printing cash move was saved to the IndexedDB and then later loaded from IndexedDB, which caused the order gets synced to the backend but missing some required fields, like preset or pricelist. opw-5969602 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262248
Documentation and clarification updates
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#278458
Original PR description
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#278458
Miscellaneous changes
load_data() reads product.pricelist.item_ids as a field, which applies _base_domain_item_ids()'s dotted active conditions. Since this runs as the cashier, never sudo, the ORM injects ir.rules into those conditions, forcing a non-hashable subquery that Postgres re-scans once per pricelist item. Cost scales with items times catalog size, freezing session opening on large catalogs. product.pricelist.item is already loaded separately via a plain, indexed pricelist_id domain. Reuse it to build ite
Original PR description
load_data() reads product.pricelist.item_ids as a field, which applies _base_domain_item_ids()'s dotted active conditions. Since this runs as the cashier, never sudo, the ORM injects ir.rules into those conditions, forcing a non-hashable subquery that Postgres re-scans once per pricelist item. Cost scales with items times catalog size, freezing session opening on large catalogs.
product.pricelist.item is already loaded separately via a plain, indexed pricelist_id domain. Reuse it to build item_ids instead of reading the field, avoiding the join/subquery entirely.
before after speedup
item_ids read 475.8s 2.44s ~195x
load_data() (full) unbounded 8.7s hang -> ok
opw-6391847
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#27725411 changes
Resolved issues and error corrections
**Steps to reproduce:** - Install l10n_pl_edi and enable Allow KSeF integration from **Accounting** settings. - Switch to a Polish company. - Create an EU customer with a valid VAT number. - Create a sale order containing a service product taxed with 0% Steel (or any tax that has a tag of K11). - Confirm the sale order and create a down payment invoice. - Send the invoice to KSeF and inspect the generated XML. **Observed behavior:** The generated KSeF XML does not contai
Original PR description
**Steps to reproduce:** - Install l10n_pl_edi and enable Allow KSeF integration from **Accounting** settings. - Switch to a Polish company. - Create an EU customer with a valid VAT number. - Create a…
**Steps to reproduce:** - Install l10n_pl_edi and enable Allow KSeF integration from **Accounting** settings. - Switch to a Polish company. - Create an EU customer with a valid VAT number. - Create a sale order containing a service product taxed with 0% Steel (or any tax that has a tag of K11). - Confirm the sale order and create a down payment invoice. - Send the invoice to KSeF and inspect the generated XML. **Observed behavior:** The generated KSeF XML does not contain the `P_13_8` field. **Cause:** For invoices involving the tax of tag `K11` (mainly these taxes are used for the supplies that are outside the territory of Poland), the value corresponding to `P_13_8` was not being assigned during XML generation, causing the tag to be omitted from the exported KSeF document. **Fix:** Populate the value of `P_13_8` during KSeF XML generation for invoices, ensuring the field is correctly included in the exported XML. This PR updates the computation of tag `P_13_10` with its test case to ensure consistency with the expected reporting logic, where the tag is computed solely from `K_31`. Here is the [Documentation](https://ksef.podatki.gov.pl/media/gtjhkeek/information-sheet-on-the-fa-3-logical-structure-04032026.pdf) link for the reference of the Ksef structure. **opw**-6294181 Forward-Port-Of: odoo/odoo#276887
Before this commit, the `empty a many2one field in list view` test sometimes failed, because the many2one value wasn't correctly unset (`first record` was selected). This happened because we cleared the input and automatically validated (typically with tab). However, it could happen that the validation occurred after the dropdown was opened, so the first value of the dropdown was selected. As a matter of fact, adding `await runAllTimers()` after clearing the input is a way to make the test fail
Original PR description
Before this commit, the `empty a many2one field in list view` test sometimes failed, because the many2one value wasn't correctly unset (`first record` was selected). This happened because we cleared…
Before this commit, the `empty a many2one field in list view` test sometimes failed, because the many2one value wasn't correctly unset (`first record` was selected). This happened because we cleared the input and automatically validated (typically with tab). However, it could happen that the validation occurred after the dropdown was opened, so the first value of the dropdown was selected. As a matter of fact, adding `await runAllTimers()` after clearing the input is a way to make the test fail deterministically. This commit avoids the issue by emptying the many2one without validation, so it basically only set the input value to the empty string, but doesn't tab/enter or anything else, hence it never selects an unwanted value. runbot error-941430 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#280351
This is rather an attempt of fix, as we couldn't reproduce the error locally or in a multi build., so we have no guarantee that this strenghtens the test. The test sometimes fails as `.o_crop_icon` can't be found within 200ms. Before that, we wait for the video element to be ready (we rely on a patch of the `isVideoReady` method of the component to know that the video is ready). Once it is, the isReady flag in the state is set to true and the CropOverlay component renders its `o_crop_icon` el
Original PR description
This is rather an attempt of fix, as we couldn't reproduce the error locally or in a multi build., so we have no guarantee that this strenghtens the test. The test sometimes fails as `.o_crop_icon`…
This is rather an attempt of fix, as we couldn't reproduce the error locally or in a multi build., so we have no guarantee that this strenghtens the test. The test sometimes fails as `.o_crop_icon` can't be found within 200ms. Before that, we wait for the video element to be ready (we rely on a patch of the `isVideoReady` method of the component to know that the video is ready). Once it is, the isReady flag in the state is set to true and the CropOverlay component renders its `o_crop_icon` element. Our guess is that we may sometimes early return in `isVideoReady`, because the component has been destroyed (a new rendering might be on the way). To ensure that we don't take that as the ready signal in the test, we now only consider that we're ready if isVideoReady returned true (i.e. no early return). runbot error-241798 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#280329
When a customer invoice is digitized through OCR, the salesperson may be set to the "Public User" instead of the internal user who uploaded the document. Steps to reproduce: - Upload a PDF invoice of an existing customer - Send the PDF to OCR - Reload the page Issue: Observe the Salesperson field: it is set to the Public User. Analysis: This occurs because when the partner is filled in, the compute of the salesperson will trigger. On SaaS this happens through the extraction c
Original PR description
When a customer invoice is digitized through OCR, the salesperson may be set to the "Public User" instead of the internal user who uploaded the document. Steps to reproduce: - Upload a PDF invoice of an existing customer - Send the PDF to OCR - Reload the page Issue: Observe the Salesperson field: it is set to the Public User. Analysis: This occurs because when the partner is filled in, the compute of the salesperson will trigger. On SaaS this happens through the extraction completion webhook a public route processed in sudo. that does not change the current user (public user). As self.env.user is the fallback of the compute, it may be set as salesperson. opw-6296330 Forward-Port-Of: odoo/odoo#279724
When a product carrying a multi-select (no_variant) attribute is added to an order by scanning its barcode, the extra price of the selected attribute value was dropped and the product was added at its base price. The order line total is computed from `price_unit` alone. The `price_extra` of a no_variant attribute is never included in the variant price (a "multi" attribute requires create_variant="no_variant"), so it only reaches the total once folded into `price_unit`. `addLineToOrder` did th
Original PR description
When a product carrying a multi-select (no_variant) attribute is added to an order by scanning its barcode, the extra price of the selected attribute value was dropped and the product was added at…
When a product carrying a multi-select (no_variant) attribute is added to an order by scanning its barcode, the extra price of the selected attribute value was dropped and the product was added at its base price. The order line total is computed from `price_unit` alone. The `price_extra` of a no_variant attribute is never included in the variant price (a "multi" attribute requires create_variant="no_variant"), so it only reaches the total once folded into `price_unit`. `addLineToOrder` did that fold-in only when the product was not scanned (`!isScannedProduct`). That guard was added to avoid counting the extra price twice when scanning an "always" variant barcode, whose extra is already part of its price. Since then, the extra price reaching this block is filtered to no_variant values only, both in the configurator and in the direct-variant branch, so an "always" extra can no longer reach it and the guard now only drops legitimate no_variant surcharges. Remove the guard so the no_variant extra price is always applied. Steps to reproduce: - Create a product with a multi-checkbox attribute whose value has an extra price, and give the product a barcode. - Open the PoS and scan the barcode. - Pick the attribute value in the configurator and validate. => The extra price is not added to the order line. opw-6413924 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278389
During the forward port of #278378, the dynamic NSI file path variable was overwritten by an old hardcoded one, breaking the IoT package build.
Original PR description
During the forward port of #278378, the dynamic NSI file path variable was overwritten by an old hardcoded one, breaking the IoT package build.
Steps to reproduce the error: (Python Version: 3.14.X) - Install ``accounting_firm`` industry with demo data Code for server action to generate the error: ```py for i in [1]: try: pass except Exception: pass if i: pass ``` Traceback: ```py ValueError: forbidden opcode(s) in'...': JUMP_BACKWARD_NO_INTERRUPT ``` https://github.com/odoo/industry/blob/701f7595453772e42ce72aa75df346a504e5bd82/accounting_firm/demo/ir_actions_server.xml#L105-L10
Original PR description
Steps to reproduce the error: (Python Version: 3.14.X) - Install ``accounting_firm`` industry with demo data Code for server action to generate the error: ```py for i in [1]: try: pass except…
Steps to reproduce the error: (Python Version: 3.14.X)
- Install ``accounting_firm`` industry with demo data
Code for server action to generate the error:
```py
for i in [1]:
try:
pass
except Exception:
pass
if i:
pass
```
Traceback:
```py
ValueError: forbidden opcode(s) in'...': JUMP_BACKWARD_NO_INTERRUPT
```
https://github.com/odoo/industry/blob/701f7595453772e42ce72aa75df346a504e5bd82/accounting_firm/demo/ir_actions_server.xml#L105-L108
The server action contains a ``for`` loop with a ``try/except`` block followed by additional statements in the loop body,
this combination generates the ``JUMP_BACKWARD_NO_INTERRUPT`` opcode, which is not included in ``_SAFE_OPCODES`` at [1].
When the server action is evaluated by ``safe_eval``, it calls the ``assert_valid_codeobj`` method, which validates the compiled bytecode against ``_SAFE_OPCODES``. Since ``JUMP_BACKWARD_NO_INTERRUPT`` is not present in the allowed opcodes, ``assert_valid_codeobj()`` raises a ``ValueError`` at [2] before the server action is executed .
Solution:
``JUMP_BACKWARD_NO_INTERRUPT`` opcode is added in the ``_SAFE_OPCODES`` and it is also added in the ``_SAFE_QWEB_OPCODES``.
It was added in Python 3.11: https://docs.python.org/3/whatsnew/3.11.html#new-opcodes
``JUMP_BACKWARD_NO_INTERRUPT`` is a control-flow opcode that only changes
the interpreter's execution flow by jumping back to a previous instruction.
It is the equivalent to ``JUMP_BACKWARD`` opcode. Its only semantic difference is
that the interpreter does not perform an interrupt check at that instruction.
It does not introduce any new capabilities or perform operations such as
attribute access, imports, function calls, or object creation.
Ref: https://docs.python.org/3.12/library/dis.html#opcode-JUMP_BACKWARD_NO_INTERRUPT
Similar commit that adds some necessary opcodes:
https://github.com/odoo/odoo/commit/86498d24946e510025add5d24ef0d4bcce8ad05f
[1]: https://github.com/odoo/odoo/blob/2ccbc4660077bd48529e9de43d4309fbfafc75ca/odoo/tools/safe_eval.py#L135
[2]: https://github.com/odoo/odoo/blob/2ccbc4660077bd48529e9de43d4309fbfafc75ca/odoo/tools/safe_eval.py#L244-L246
sentry-7614026125
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#277192The getter `getLoadedDataSources` was filtering out datasources that are not 'ready' but they should actually filter out datasources that were already loaded (so ready) but invalid. Task: 6387729 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#276255
Original PR description
The getter `getLoadedDataSources` was filtering out datasources that are not 'ready' but they should actually filter out datasources that were already loaded (so ready) but invalid. Task: 6387729 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#276255
## Issue When logging timesheet from the *Recorded* smart button on a Sale Order containing multiple service items, the recorded hours will be added to the first sale order line, regardless of the task ID set on the timesheet entries. ## Steps to reproduce 1. Install *Sales Timesheet* (`sale_timesheet`) 2. Create a Product P: - *Product Type*: Service - *Create on Order*: Task - *Project*: Any 3. Create a SO: - *Customer*: Any - Add the product P on two different
Original PR description
## Issue When logging timesheet from the *Recorded* smart button on a Sale Order containing multiple service items, the recorded hours will be added to the first sale order line, regardless of the…
## Issue
When logging timesheet from the *Recorded* smart button on a Sale Order containing multiple service items, the recorded hours will be added to the first sale order line, regardless of the task ID set on the timesheet entries.
## Steps to reproduce
1. Install *Sales Timesheet* (`sale_timesheet`)
2. Create a Product P:
- *Product Type*: Service
- *Create on Order*: Task
- *Project*: Any
3. Create a SO:
- *Customer*: Any
- Add the product P on two different lines and give them two different descriptions D1 and D2
- Confirm the SO, this will create two tasks with the names D1 and D2
4. On the SO, click the *Recorded* smart button and create two entries:
1. Task D1, 2 hours spent
2. Tsk D2, 3 hours spent
5. **Back on the SO, there are 5 hours registered for the first SOL (with the description D1), which does not match the entries we created from the smart button.**
It is worth noting that when we create the Timesheets entries from the project itself (instead of the SO's smart button), the hours are correctly distributed among the different SOLs.
## Cause
The SOL linked to the timesheet entry (`account.analytic.line`) is computed by `_compute_so_line`:
https://github.com/odoo/odoo/blob/8b102f500f5a122e99b07a08cc43814e7c6f0f75/addons/sale_timesheet/models/hr_timesheet.py#L79-L82
This method sets the correct SOL under the condition that `is_so_line_edited` is False and `_is_no_billed()` returns True.
When opening the *Recorded* smart button from a SO, the `is_so_line_edited` is set to True by default, even if no SOL was modified.
https://github.com/odoo/odoo/blob/8b102f500f5a122e99b07a08cc43814e7c6f0f75/addons/sale_timesheet/models/sale_order.py#L113-L117
As that value is never set to False, when trying to compute the SOL for the timesheet entry, the entry is skipped and the default SOL (which is the first one) is used instead.
opw-6133473
Forward-Port-Of: odoo/odoo#274759Issue: --- 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#278974 Forward-Port-Of: odoo/odoo#276485
Documentation and clarification updates
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#278458
Original PR description
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#278458
5 changes
Resolved issues and error corrections
Following the change in https://github.com/odoo/odoo/pull/225544 we added a timezone to `jules_emp` to avoid discrepancies when running the tests with and without demo data. However the `resource_calendar_id` of the contract used by this employee didn't have a timezone leading to similar errors in other tests. This commit adds the same timezone to the calendar used by test employee to prevent the errors. [error-938862 ](https://runbot.odoo.com/odoo/error/938862) --- I confirm I h
Original PR description
Following the change in https://github.com/odoo/odoo/pull/225544 we added a timezone to `jules_emp` to avoid discrepancies when running the tests with and without demo data. However the `resource_calendar_id` of the contract used by this employee didn't have a timezone leading to similar errors in other tests. This commit adds the same timezone to the calendar used by test employee to prevent the errors. [error-938862 ](https://runbot.odoo.com/odoo/error/938862) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
#### Description of the issue this PR addresses: - The predicate loop kept climbing ancestors above the editable root when no match was found inside it. The later containment check would discard such a match anyway, so the predicate should never run outside the editable in the first place. - This ran the predicate on at least 14 unnecessary ancestors up to `<html>`, costly if the predicate is expensive. Stop the search at the editable boundary instead. - `movenode_plugin` calls closestElement
Original PR description
#### Description of the issue this PR addresses: - The predicate loop kept climbing ancestors above the editable root when no match was found inside it. The later containment check would discard such a match anyway, so the predicate should never run outside the editable in the first place. - This ran the predicate on at least 14 unnecessary ancestors up to `<html>`, costly if the predicate is expensive. Stop the search at the editable boundary instead. - `movenode_plugin` calls closestElement on every mousemove, so its predicate was needlessly re-evaluated on those 14+ ancestors on every single mouse move. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Description of the issue this commit addresses: The invoice product prediction test requires account_accountant but runs and fails when that optional module is not installed. --- Desired behavior after this commit is merged: This commit skips the test when account_accountant is not installed and enables product prediction when it is available. --- runbot-[941525](https://runbot.odoo.com/odoo/error/941525) --- I confirm I have signed the CLA and read the PR guidelines at w
Original PR description
Description of the issue this commit addresses: The invoice product prediction test requires account_accountant but runs and fails when that optional module is not installed. --- Desired behavior after this commit is merged: This commit skips the test when account_accountant is not installed and enables product prediction when it is available. --- runbot-[941525](https://runbot.odoo.com/odoo/error/941525) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Miscellaneous changes
Support for multiple employees per user Use Case Example: - Create Company A and Company B - Create a user named Test with access to both companies - Create an employee named Test A linked to Company A and the Test user - Create an employee named Test B linked to Company B and the Test user - Log in as the Test user with only Company A selected. Everything should be linked to employee Test A - Log in as the Test user with only Company B selected. Everything should be linked to employee
Original PR description
Support for multiple employees per user Use Case Example: - Create Company A and Company B - Create a user named Test with access to both companies - Create an employee named Test A linked to Company A and the Test user - Create an employee named Test B linked to Company B and the Test user - Log in as the Test user with only Company A selected. Everything should be linked to employee Test A - Log in as the Test user with only Company B selected. Everything should be linked to employee Test B Please @pedrobaeza can you review it? @Tecnativa TT63466 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The product specifications table is displayed whenever the product has tags, even if none of them are visible on the ecommerce website. The product tags template filters out non-visible tags, but the surrounding table remains rendered and appears empty. Only display the tags table when at least one tag is visible on ecommerce. @Tecnativa TT63855 **Description of the issue/feature this PR addresses:** The condition used to display the product tags table considers all tags associate
Original PR description
The product specifications table is displayed whenever the product has tags, even if none of them are visible on the ecommerce website. The product tags template filters out non-visible tags, but the…
The product specifications table is displayed whenever the product has tags, even if none of them are visible on the ecommerce website. The product tags template filters out non-visible tags, but the surrounding table remains rendered and appears empty. Only display the tags table when at least one tag is visible on ecommerce. @Tecnativa TT63855 **Description of the issue/feature this PR addresses:** The condition used to display the product tags table considers all tags associated with the product, including those that are not visible on ecommerce. **Current behavior before PR:** When a product only has non-visible tags, the tags table is displayed without any content. <img width="669" height="350" alt="image" src="https://github.com/user-attachments/assets/4758ea76-5186-4035-a065-aa4c71ce7053" /> **Desired behavior after PR is merged:** The tags table is only displayed when the product has at least one tag visible on ecommerce. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278604
6 changes
Resolved issues and error corrections
Steps to reproduce: - Install pos_loyalty and pos_online_payment. - Configure a nominative loyalty program (trigger=auto, applies_on=both) awarding points, and an online payment method. - In the PoS, add a first-time customer and a product, then pay the order with the online payment method. Issue: The customer earns no point, and no loyalty.card is even created for a first-time customer. Orders paid in cash are not affected. The loss is intermittent for customers whose card is already cac
Original PR description
Steps to reproduce: - Install pos_loyalty and pos_online_payment. - Configure a nominative loyalty program (trigger=auto, applies_on=both) awarding points, and an online payment method. - In the PoS,…
Steps to reproduce: - Install pos_loyalty and pos_online_payment. - Configure a nominative loyalty program (trigger=auto, applies_on=both) awarding points, and an online payment method. - In the PoS, add a first-time customer and a product, then pay the order with the online payment method. Issue: The customer earns no point, and no loyalty.card is even created for a first-time customer. Orders paid in cash are not affected. The loss is intermittent for customers whose card is already cached. Cause: Once paid, the order is rebuilt from the server data and re-selected. `pos.order._export_for_ui` has no `couponPointChanges` field, so the rebuilt order starts with an empty one. `set_order` does schedule a recompute, but it does not await it, and `_postPushOrderResolve` reads `couponPointChanges` right after, before the recompute settles, hence sending nothing to `confirm_coupon_programs`. A first-time customer additionally needs a `fetchLoyaltyCard` RPC, so the recompute can never win the race. Fix: Wait for the pending recompute before compiling the coupon data. `Mutex.getUnlockedDef` is used rather than awaiting a new `_updateRewards` call, so that no extra recompute is queued on an order that is already finalized and saved on the server. 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
Sometimes the default_state remains in the context from a past action and when the subcontractor fills its components consumptions it will directly modify the quant's quantity. This trigger the automatic rules and generate an unwanted picking opw-6109661 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
Original PR description
Sometimes the default_state remains in the context from a past action and when the subcontractor fills its components consumptions it will directly modify the quant's quantity. This trigger the automatic rules and generate an unwanted picking opw-6109661 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
Description of the issue/feature this PR addresses: A user without accounting rights cannot open an invoice form when l10n_es_edi_verifactu is installed. The module adds a VeriFactu page and three warning banners to the standard invoice form without any groups restriction, so every user able to open an invoice reads three fields (l10n_es_edi_verifactu_document_ids, l10n_es_edi_verifactu_warning, l10n_es_edi_verifactu_warning_level) pointing at l10n_es_edi_verifactu.document. That model
Original PR description
Description of the issue/feature this PR addresses: A user without accounting rights cannot open an invoice form when l10n_es_edi_verifactu is installed. The module adds a VeriFactu page and three…
Description of the issue/feature this PR addresses: A user without accounting rights cannot open an invoice form when l10n_es_edi_verifactu is installed. The module adds a VeriFactu page and three warning banners to the standard invoice form without any groups restriction, so every user able to open an invoice reads three fields (l10n_es_edi_verifactu_document_ids, l10n_es_edi_verifactu_warning, l10n_es_edi_verifactu_warning_level) pointing at l10n_es_edi_verifactu.document. That model only grants read access to account.group_account_invoice and account.group_account_readonly. Steps to reproduce: - install `l10n_es_edi_verifactu` - create a salesman user with sales rights but no accounting right (*Own Documents Only* is enough) - create an ES company and an ES customer - give the salesman access to the ES company - activate Peppol in the general settings - log in as the salesman - create a sale order in the ES company for the ES customer - confirm it - click **Create Invoice** - click **Create Draft** Current behavior before PR: An error access is raised: Failed to read field account.move.l10n_es_edi_verifactu_document_ids You are not allowed to access 'Veri*Factu Document' (l10n_es_edi_verifactu.document) records. This operation is allowed for the following groups: - Invoicing/Billing - Technical/Show Accounting Features - Readonly Contact your administrator to request access if necessary. In Odoo sh (for databases 19.0), the standard test sale_management / TestSaleFlowTourPostInstall.test_basic_sale_flow_with_minimal_access_rights fails for the same reason as soon as l10n_es_edi_verifactu is installed alongside sale_management. Desired behavior after PR is merged: On a database with l10n_es_edi_verifactu installed, a non-accountant user having the possibility to create invoices should not have the error message displayed. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
When edit_translations is set, convert_to_record wraps translated terms in branding spans. Related (non-stored) fields re-read that already-wrapped value and ran the same wrapping again, producing nested spans. Only wrap terms for stored fields so related Html inherits the source branding unchanged. Also keep data-oe-translation-state in HTML safe_attrs so sanitization does not strip it. Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior af
Original PR description
When edit_translations is set, convert_to_record wraps translated terms in branding spans. Related (non-stored) fields re-read that already-wrapped value and ran the same wrapping again, producing nested spans. Only wrap terms for stored fields so related Html inherits the source branding unchanged. Also keep data-oe-translation-state in HTML safe_attrs so sanitization does not strip it. 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
Description of the issue/feature this PR addresses: Portal/public users get AccessError (HTTP 403) when kit product stock fields are read on the website shop or cart. Kits (phantom BoMs) have no on-hand stock of their own: `qty_available` / `free_qty` are derived by finding the BoM, exploding components, and computing how many complete kits can be built. Shop and cart code read those fields for availability (in stock / out of stock, prevent selling more than available, etc.). Portal users are
Original PR description
Description of the issue/feature this PR addresses: Portal/public users get AccessError (HTTP 403) when kit product stock fields are read on the website shop or cart. Kits (phantom BoMs) have no…
Description of the issue/feature this PR addresses: Portal/public users get AccessError (HTTP 403) when kit product stock fields are read on the website shop or cart. Kits (phantom BoMs) have no on-hand stock of their own: `qty_available` / `free_qty` are derived by finding the BoM, exploding components, and computing how many complete kits can be built. Shop and cart code read those fields for availability (in stock / out of stock, prevent selling more than available, etc.). Portal users are not meant to manage BOMs (no ACL on `mrp.bom`), and kit components are often not website-published, so the base `_compute_quantities_dict` path blows up on a normal shop browse. `website_sale_mrp` already avoids this for cart checks by reading `product.sudo().free_qty`; the product quantity compute did not. This affects 17.0+ (verified on 17.0 and 19.0). Targeting 17.0 as the oldest supported branch so it can be forward-ported. CLA: covered by https://github.com/odoo/odoo/pull/275749 Current behavior before PR: Reading kit stock fields (e.g. on the shop) as a portal/public user raises AccessError when the BoM or unpublished components must be read. Desired behavior after PR is merged: For portal/public users, kit quantity computation runs under `sudo()` (same idea as `website_sale_mrp`). BOMs stay unreadable to portal users directly. Regression test covers portal and public access. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
In ubuntu 26.04 the time zone database contents changed. A couple of timezone names are not available anymore, causing runtime exceptions. This mapping links old with new time zone naming conventions to prevent future (test) breakdown. The mapping WET to Europe/Lisbon is imperfect, and the localizations for the fixed date inside the test did not match. There exists no better nor correct mapping for WET. The mapping to Europe/Lisbon comes from the IANA tzdb-2026c and is official, so it
Original PR description
In ubuntu 26.04 the time zone database contents changed. A couple of timezone names are not available anymore, causing runtime exceptions. This mapping links old with new time zone naming conventions to prevent future (test) breakdown. The mapping WET to Europe/Lisbon is imperfect, and the localizations for the fixed date inside the test did not match. There exists no better nor correct mapping for WET. The mapping to Europe/Lisbon comes from the IANA tzdb-2026c and is official, so it is kept unchanged. The fixed date inside the test is changed to a recent one that aligns the test outcome with expectations: - Offsets match for recent history and future time - Match daylight savings time (DST) observation --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr