Daily updates from Odoo
Monday, August 3, 2026
281 changes
11 changes
Resolved issues and error corrections
The `bus_monitoring_service` test "connection considered as lost after failed reconnect attempt" fails about half of the time. Since [1], the reconnect delay in tests is much smaller. The retry therefore fires while the mock socket is still in the closing state. `_start` detects that socket and triggers the close event manually to keep the lifecycle consistent. In other cases, the error event will schedule a reconnect but in this case it will never arrive. The worker is then left with n
Original PR description
The `bus_monitoring_service` test "connection considered as lost after failed reconnect attempt" fails about half of the time. Since [1], the reconnect delay in tests is much smaller. The retry…
The `bus_monitoring_service` test "connection considered as lost after failed reconnect attempt" fails about half of the time. Since [1], the reconnect delay in tests is much smaller. The retry therefore fires while the mock socket is still in the closing state. `_start` detects that socket and triggers the close event manually to keep the lifecycle consistent. In other cases, the error event will schedule a reconnect but in this case it will never arrive. The worker is then left with no socket, no listeners and no pending timeout: it never reconnects. Schedule the reconnection when handling a manually triggered close, since no error event will follow to do it. [1]: https://github.com/odoo/odoo/pull/278075 runbot-944578 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#279046 Forward-Port-Of: odoo/odoo#278779
### Steps to reproduce: - Enable developer mode - Go to Settings > Technical > Messages > ValueError: Cannot search, too many messages ### Cause of Issue: The new `ir.access` model introduced through https://github.com/odoo/odoo/pull/166359 inherits from `mail.thread` and enables tracking on the `active`, `domain`, and `operation` fields. https://github.com/odoo/odoo/blob/713f68333798575d70362cbb55ca31e91e75d5fa/addons/mail/models/ir_access.py#L7-L12 In production databases, every acce
Original PR description
### Steps to reproduce: - Enable developer mode - Go to Settings > Technical > Messages > ValueError: Cannot search, too many messages ### Cause of Issue: The new `ir.access` model introduced through…
### Steps to reproduce: - Enable developer mode - Go to Settings > Technical > Messages > ValueError: Cannot search, too many messages ### Cause of Issue: The new `ir.access` model introduced through https://github.com/odoo/odoo/pull/166359 inherits from `mail.thread` and enables tracking on the `active`, `domain`, and `operation` fields. https://github.com/odoo/odoo/blob/713f68333798575d70362cbb55ca31e91e75d5fa/addons/mail/models/ir_access.py#L7-L12 In production databases, every access rule modification generates a tracking message on the corresponding `ir.access` record. When a user opens Settings > Technical > Messages without any model filter, `_search_res_access` falls into the "enumerate all messages" path since no specific model is constrained in the domain. https://github.com/odoo/odoo/blob/713f68333798575d70362cbb55ca31e91e75d5fa/addons/mail/models/mail_message.py#L469-L473 This path calls `_filter_accessible_from_query`, which fetches messages up to `MAX_SEARCH_LIMIT` (= `PREFETCH_MAX * 10` = 10 000). https://github.com/odoo/odoo/blob/713f68333798575d70362cbb55ca31e91e75d5fa/addons/mail/models/mail_message.py#L614-L615 Because `ir.access` tracking messages alone can exceed that limit, the guard raises: > ValueError: Cannot search, too many messages ### Fix: Exclude messages whose `model` is `ir.access` from the enumeration domain when fetching generic messages to ensure important information is present without exceeding the messages limit. When the user's search domain already constrains the model to `ir.access` (e.g., when opening the chatter of a specific access rule record), `condition_values()` detects the model constraint and the per-model SQL path is taken instead — so those messages remain fully accessible in their own context. opw-6364325
The time taken by the AI to generate the placeholders during the configurator loading is sometimes exacly or slightly over 15 seconds, which results in a timeout. This commit increase the timeout time to 30 seconds. Also we lowered the translated ratio from 80% to 70% because some themes had a low translation ratio. task-6325919
Original PR description
The time taken by the AI to generate the placeholders during the configurator loading is sometimes exacly or slightly over 15 seconds, which results in a timeout. This commit increase the timeout time to 30 seconds. Also we lowered the translated ratio from 80% to 70% because some themes had a low translation ratio. task-6325919
**PROBLEM** When creating a Credit Note from a Sale Order, the credit note lines uses the default account instead of using the return account set on the company. **STEP TO REPRODUCE** 1. Create a SO with a product. 2. Create an invoice and confirm it. 3. Return to the SO, and reduce the product qty (product invoice policy should be ordered qty for these steps). 4. Click again on create Invoice to create a Credit Note for the SO. 5. Notice the account on the product line is not the retur
Original PR description
**PROBLEM** When creating a Credit Note from a Sale Order, the credit note lines uses the default account instead of using the return account set on the company. **STEP TO REPRODUCE** 1. Create a SO with a product. 2. Create an invoice and confirm it. 3. Return to the SO, and reduce the product qty (product invoice policy should be ordered qty for these steps). 4. Click again on create Invoice to create a Credit Note for the SO. 5. Notice the account on the product line is not the return account. **CAUSE** In `_create_invoices()` on the SO model, we first create the moves as invoice, and then switch them to credit note if the total is negative. This means the lines are created with the invoice default account. opw-6266882 Forward-Port-Of: odoo/odoo#274354
**Issue** The package of the selected quant is not proposed as a destination package when adding stock move lines manually before the move line is saved. **Steps to reproduce** - Activate 'Packages' in the settings - Create a tracked product with package - Put 10 units in stock in package `P`. - Create and confirm a sale for 5 units - Open the delivery, make sure the quantity is set to 0 - Click 'Details' - "Add a line" and select the package P -> if you try to select a destination p
Original PR description
**Issue** The package of the selected quant is not proposed as a destination package when adding stock move lines manually before the move line is saved. **Steps to reproduce** - Activate 'Packages'…
**Issue** The package of the selected quant is not proposed as a destination package when adding stock move lines manually before the move line is saved. **Steps to reproduce** - Activate 'Packages' in the settings - Create a tracked product with package - Put 10 units in stock in package `P`. - Create and confirm a sale for 5 units - Open the delivery, make sure the quantity is set to 0 - Click 'Details' - "Add a line" and select the package P -> if you try to select a destination package, the package P is not proposed as it should - save it and reopen 'Details' -> if you try to select a destination package, the package P is now proposed **Cause** The domain of `result_package_id` (destination package) correctly includes `package_id`: https://github.com/odoo/odoo/blob/3a5f7431effd4b2b2eb8ce3eed81aaba42fcd8ea/addons/stock/models/stock_move_line.py#L52-L56 However, before saving, `package_id` is not yet populated into the new `stock.move.line` record. It will only be copied from `quant_id` by `_copy_quant_info()`: https://github.com/odoo/odoo/blob/3a5f7431effd4b2b2eb8ce3eed81aaba42fcd8ea/addons/stock/models/stock_move_line.py#L1016-L1025 which will only be called in the create method, while saving: https://github.com/odoo/odoo/blob/3a5f7431effd4b2b2eb8ce3eed81aaba42fcd8ea/addons/stock/models/stock_move_line.py#L350 opw-6370159 Forward-Port-Of: odoo/odoo#277797
Before this commit, the unread banner could stop showing in a channel until it was left and opened again: - open a channel with unread messages - click "Mark as Read" - read the same channel from another device - receive a new message: the server counter increases, still no banner This happens because an implicit mark as read freezes the local unread state, so the banner stays in place while the user reads. The problem is that it stays frozen even after the banner is gone, and never fol
Original PR description
Before this commit, the unread banner could stop showing in a channel until it was left and opened again: - open a channel with unread messages - click "Mark as Read" - read the same channel from another device - receive a new message: the server counter increases, still no banner This happens because an implicit mark as read freezes the local unread state, so the banner stays in place while the user reads. The problem is that it stays frozen even after the banner is gone, and never follows the server counter again. This commit freezes that state only while something is still unread locally. This also fixes the flaky test "no unread message banner after message is deleted". https://runbot.odoo.com/odoo/error/242776 Forward-Port-Of: odoo/odoo#279601 Forward-Port-Of: odoo/odoo#279195
added tags for accounts and new demo data for l10n_cl_reports f29 refactor refactor file to company_demo.xml Add widthholding tax 2nd category for 2027 and 2028 since it is suitable for this report compatibility [FIX] l10n_cl: add more taxes and fix translation [FIX] l10n_cl: adapt fiscal position to new scheme. [FIX] l10n_cl: remove unused tags [FIX] l10n_cl: add fiscal position to taxes and replacement tax. Change refs in demo and fix demo values to make more consistent with real cases
Original PR description
added tags for accounts and new demo data for l10n_cl_reports f29 refactor refactor file to company_demo.xml Add widthholding tax 2nd category for 2027 and 2028 since it is suitable for this report compatibility [FIX] l10n_cl: add more taxes and fix translation [FIX] l10n_cl: adapt fiscal position to new scheme. [FIX] l10n_cl: remove unused tags [FIX] l10n_cl: add fiscal position to taxes and replacement tax. Change refs in demo and fix demo values to make more consistent with real cases [FIX] l10n_cl: change monthy taxes payable 210760 from payable to current [FIX] l10n_cl: add new ILA accounts to COA and fix ILA tax repartition lines Compatibility with 'remove tax_tag_invert' [FIX] l10n_cl: fix 'compras de combustibles' task-4329648 Forward-Port-Of: odoo/odoo#247545
With the Shared Customer Account setting enabled, a user created in c1 cannot access the shop in the website of c2 Steps to reproduce: 1. Install eCommerce and Contacts 2. Go to Settings > Users & Companies > Companies and create two companies c1 and c2 3. Go to Website > Configuration > Websites and create two websites w1 with company c1 and w2 with company c2 4. Change the order of the websites so that w1 is at the top 5. Go to Website > eCommerce > Pricelists and create a pricelist pl
Original PR description
With the Shared Customer Account setting enabled, a user created in c1 cannot access the shop in the website of c2 Steps to reproduce: 1. Install eCommerce and Contacts 2. Go to Settings > Users &…
With the Shared Customer Account setting enabled, a user created in c1 cannot access the shop in the website of c2 Steps to reproduce: 1. Install eCommerce and Contacts 2. Go to Settings > Users & Companies > Companies and create two companies c1 and c2 3. Go to Website > Configuration > Websites and create two websites w1 with company c1 and w2 with company c2 4. Change the order of the websites so that w1 is at the top 5. Go to Website > eCommerce > Pricelists and create a pricelist pl1 in c1 assigned to w1 and pl2 in c2 assigned to w2 6. In an incognito tab, go to w1 and create a new account 7. As admin, go to Website > Configuration > Websites and change the order of the websites so that w2 is at the top 8. In an incognito tab, connect with the previously created account and go to the shop 9. An error is thrown (This error only happens when geoip works, i.e. when `_get_geoip_country_code` returns something) Issue: When geoip returns a country code, we search through all the pricelists available for that country code but some of them can be restricted to a company which raises an access error. We need to be able to access them in order to filter the ones that are not available on the current website Solution: Access all pricelists with sudo, they will be filtered out with `_is_available_on_website` opw-3574089 Forward-Port-Of: odoo/odoo#279697 Forward-Port-Of: odoo/odoo#268863
Before this commit, pressing Enter or Ctrl+Enter after editing the custom favorite filter name could save the previous value instead of the latest one. This happened because `t-model.trim` synchronizes the model on the `change` event. Since the save action is triggered on `keydown`, the latest input value had not yet been propagated to the component state. This commit removes `.trim` from `t-model` and trims the description only during the save operation, ensuring the latest value is used
Original PR description
Before this commit, pressing Enter or Ctrl+Enter after editing the custom favorite filter name could save the previous value instead of the latest one. This happened because `t-model.trim` synchronizes the model on the `change` event. Since the save action is triggered on `keydown`, the latest input value had not yet been propagated to the component state. This commit removes `.trim` from `t-model` and trims the description only during the save operation, ensuring the latest value is used while preserving the existing validation against empty or whitespace-only names. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279620 Forward-Port-Of: odoo/odoo#273593
In the `render_task_templates` branch, the `has_template_ancestor` step called `.toList({})`, turning `domain` into a plain list. It was only rebuilt into a `Domain` when a `default_project_id` was in context, so otherwise the trailing `domain.toList({})` threw `TypeError: domain.toList is not a function`. Introduced in 694ea6a2fb60 (odoo/odoo#279015). Fix: drop the premature `.toList({})` so `domain` stays a `Domain` until the single final conversion. Appeared on many clickAll failures assig
Original PR description
In the `render_task_templates` branch, the `has_template_ancestor` step called `.toList({})`, turning `domain` into a plain list. It was only rebuilt into a `Domain` when a `default_project_id` was in context, so otherwise the trailing `domain.toList({})` threw `TypeError: domain.toList is not a function`.
Introduced in 694ea6a2fb60 (odoo/odoo#279015).
Fix: drop the premature `.toList({})` so `domain` stays a `Domain` until the single final conversion.
Appeared on many clickAll failures assigned to the JS team:
https://runbot.odoo.com/odoo/error/944607Steps to Reproduce the Error (Odoo SaaS 19.2): 1. Install l10n_gcc_invoice localization & Accounting 2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings > Configuration > Customer Invoices > Default Terms and Conditions 3. Create invoice with ar_001 partner 4. Confirm the invoice 5. Try to create credit note → Error: KeyError: 'en_US' Root Cause: The _load_narration_translation() workaround reads raw invoice_terms from DB and injects the entire JSONB di
Original PR description
Steps to Reproduce the Error (Odoo SaaS 19.2): 1. Install l10n_gcc_invoice localization & Accounting 2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings >…
Steps to Reproduce the Error (Odoo SaaS 19.2):
1. Install l10n_gcc_invoice localization & Accounting
2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings > Configuration > Customer Invoices > Default Terms and Conditions
3. Create invoice with ar_001 partner
4. Confirm the invoice
5. Try to create credit note → Error: KeyError: 'en_US'
Root Cause:
The _load_narration_translation() workaround reads raw invoice_terms from DB and injects the entire JSONB dict directly into cache, bypassing ORM field conversion. When Odoo 19.2's improved ORM conversion runs, it creates nested JSON in narration instead of a flat structure.
Timeline:
- bedf1cb66fbb: Workaround added to prevent T&C duplication in preview
- 75f050b9650d: Root cause fixed in report template (conditional display) → Made _load_narration_translation() redundant
- 4e4156536bc9: Odoo 19.2 improved ORM conversion → Now conflicts with the redundant workaround, causing nested JSON
How It Breaks:
1. Invoice creation: _load_narration_translation() injects raw dict into cache
2. ORM writes: nested JSON stored: {ar_001: {en_US: ., ar_001: Arabic}}
3. Credit note creation: copy_translations() expects flat structure → Crashes: KeyError: 'en_US'
Why It's Safe to Remove:
Report template already prevents T&C duplication (commit 75f050b9650d). Removing the workaround restores proper credit note creation without breaking T&C display.
Changes:
- Remove moves._load_narration_translation() in create()
- Remove out self.filtered('id')._load_narration_translation() in _compute_narration()
opw : 6284943
Forward-Port-Of: odoo/odoo#27103723 changes
Enhancements to existing features
Steps to reproduce: 1. Create a sales order. 2. Confirm or cancel the order. 3. Share the quotation link. 4. Open the quotation from an incognito window or the customer portal. Issue: - A 'Quotation Viewed by Customer' notification is sent even though the document is no longer an active quotation. Fix: - Only send the notification while the order is in quotation or quotation sent state. opw-6419364 Forward-Port-Of: odoo/odoo#278633
Original PR description
Steps to reproduce: 1. Create a sales order. 2. Confirm or cancel the order. 3. Share the quotation link. 4. Open the quotation from an incognito window or the customer portal. Issue: - A 'Quotation Viewed by Customer' notification is sent even though the document is no longer an active quotation. Fix: - Only send the notification while the order is in quotation or quotation sent state. opw-6419364 Forward-Port-Of: odoo/odoo#278633
Resolved issues and error corrections
To reproduce on runbot: - Log-in as "demo" user - Open a chat discussion (bubble window) with "OdooBot" (you can leave it open or fold it) - Log-out - Log-in as "admin" user It crash with: ``` TypeError: can't access property "imStatusUI", this.channel.correspondent is undefined ``` This commit ensure we don't crash if user is not a member of the channel anymore. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
To reproduce on runbot: - Log-in as "demo" user - Open a chat discussion (bubble window) with "OdooBot" (you can leave it open or fold it) - Log-out - Log-in as "admin" user It crash with: ``` TypeError: can't access property "imStatusUI", this.channel.correspondent is undefined ``` This commit ensure we don't crash if user is not a member of the channel anymore. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Steps to produce: --- - Install the Sales module. - Enable `Pricelists` from Sales settings. - Create a new product. - Go to Sales > Products > Pricelists and open an existing pricelist. - Add the following rules for a product: - min qty: 1 > price: 100 - min qty:10 > price: 80 - Create a new quotation > add section > add the same product. - Set the section as optional > Preview the quotation. - Change its quantity to 10. Added test covering the fix introduced in [com
Original PR description
Steps to produce:
---
- Install the Sales module.
- Enable `Pricelists` from Sales settings.
- Create a new product.
- Go to Sales > Products > Pricelists and open an existing pricelist.
- Add the following rules for a product:
- min qty: 1 > price: 100
- min qty:10 > price: 80
- Create a new quotation > add section > add the same product.
- Set the section as optional > Preview the quotation.
- Change its quantity to 10.
Added test covering the fix introduced in [commit], ensuring
that pricelist rules are correctly reapplied when the quantity of an
optional product is changed from the quotation preview.
[commit]: https://github.com/odoo/odoo/commit/93b6bdd6a4909bc0b45b90ab6a2d0734a218292d
opw-6241183
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#279135
Forward-Port-Of: odoo/odoo#266597Version: -------- - 19.0+ Steps to reproduce: ------------------- - Install `mrp` module - Go to the setting enable `Lots & Serial Numbers` and `Storage Locations` - Create a storable product tracked by Lots - Configure a Putaway Rule for the product so it is stored in a sub-location - Create a Bill of Materials for the product with at least one component - Create and confirm a Manufacturing Order - Increase the production quantity (e.g. using the "Change Production Quantit
Original PR description
Version: -------- - 19.0+ Steps to reproduce: ------------------- - Install `mrp` module - Go to the setting enable `Lots & Serial Numbers` and `Storage Locations` - Create a storable product tracked…
Version:
--------
- 19.0+
Steps to reproduce:
-------------------
- Install `mrp` module
- Go to the setting enable `Lots & Serial Numbers` and `Storage Locations`
- Create a storable product tracked by Lots
- Configure a Putaway Rule for the product so it is stored in a
sub-location
- Create a Bill of Materials for the product with at least one
component
- Create and confirm a Manufacturing Order
- Increase the production quantity (e.g. using the "Change Production
Quantity" wizard)
- Click **Generate Lot/Serial Number**
- Click **Produce All**
Issue:
------
Completing the Manufacturing Order raises:
Invalid Operation
You need to supply a Lot/Serial Number for product:
- Product
even though a single lot should be sufficient for a lot-tracked
product.
Cause:
------
When the production quantity is increased, `change_prod_qty()` updates
the finished move's demanded quantity and re-reserves it through
`_update_finished_moves()`:
https://github.com/odoo/odoo/blob/154b49ec6be6230989ee4eb420e7f83b681ff520/addons/mrp/wizard/change_production_qty.py#L77
which calls `_action_assign()` on the finished move:
https://github.com/odoo/odoo/blob/154b49ec6be6230989ee4eb420e7f83b681ff520/addons/mrp/wizard/change_production_qty.py#L49
Since finished moves originate from the production location, they
bypass the normal reservation flow:
https://github.com/odoo/odoo/blob/154b49ec6be6230989ee4eb420e7f83b681ff520/addons/stock/models/stock_move.py#L2070
`_action_assign()` then tries to reuse the move's existing move line,
but the lookup requires `location_dest_id` to still match the move's
generic destination:
https://github.com/odoo/odoo/blob/154b49ec6be6230989ee4eb420e7f83b681ff520/addons/stock/models/stock_move.py#L2092-L2106
That existing line's `location_dest_id` was already redirected to the
putaway sub-location by the previous `_apply_putaway_strategy()` call
(at MO confirmation), so the lookup no longer matches and a second,
distinct move line is created and appended instead of the first one
being reused:
https://github.com/odoo/odoo/blob/154b49ec6be6230989ee4eb420e7f83b681ff520/addons/stock/models/stock_move.py#L2170
Later, clicking **Generate Lot/Serial Number** creates a single lot and
stores it on the production order's `lot_producing_ids`:
https://github.com/odoo/odoo/blob/154b49ec6be6230989ee4eb420e7f83b681ff520/addons/mrp/models/mrp_production.py#L1602
When **Produce All** is clicked, which trigger `button_mark_done()` it calls
`_post_inventory()`:
https://github.com/odoo/odoo/blob/154b49ec6be6230989ee4eb420e7f83b681ff520/addons/mrp/models/mrp_production.py#L2227
which assigns that lot to the finished move through `move.lot_ids`:
https://github.com/odoo/odoo/blob/154b49ec6be6230989ee4eb420e7f83b681ff520/addons/mrp/models/mrp_production.py#L1925
Since `lot_ids` is declared with `inverse='_set_lot_ids'`, this write
triggers that inverse method:
https://github.com/odoo/odoo/blob/154b49ec6be6230989ee4eb420e7f83b681ff520/addons/stock/models/stock_move.py#L192
The current implementation of `_set_lot_ids()` only assigns the lot to
a single available move line, regardless of tracking type:
https://github.com/odoo/odoo/blob/154b49ec6be6230989ee4eb420e7f83b681ff520/addons/stock/models/stock_move.py#L656-L668
Since only one lot is ever generated for a lot-tracked product, only
the first finished move line receives a `lot_id`. The second move line
created after increasing the production quantity is left without one.
When `button_mark_done()` validates the finished move lines, it
detects that one of them still has no lot assigned and raises the
"Invalid Operation" error, even though a single lot is valid for the
entire production of a lot-tracked product.
Fix:
----
`action_generate_serial` produces a single lot for the whole production.
In `_post_inventory()`, right after the generated lot is set on
the finished move, propagate it to any remaining lot-less move lines
of a **lot**-tracked finished move.
---
opw-6366060
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#277819
Forward-Port-Of: odoo/odoo#275000The `bus_monitoring_service` test "connection considered as lost after failed reconnect attempt" fails about half of the time. Since [1], the reconnect delay in tests is much smaller. The retry therefore fires while the mock socket is still in the closing state. `_start` detects that socket and triggers the close event manually to keep the lifecycle consistent. In other cases, the error event will schedule a reconnect but in this case it will never arrive. The worker is then left with n
Original PR description
The `bus_monitoring_service` test "connection considered as lost after failed reconnect attempt" fails about half of the time. Since [1], the reconnect delay in tests is much smaller. The retry…
The `bus_monitoring_service` test "connection considered as lost after failed reconnect attempt" fails about half of the time. Since [1], the reconnect delay in tests is much smaller. The retry therefore fires while the mock socket is still in the closing state. `_start` detects that socket and triggers the close event manually to keep the lifecycle consistent. In other cases, the error event will schedule a reconnect but in this case it will never arrive. The worker is then left with no socket, no listeners and no pending timeout: it never reconnects. Schedule the reconnection when handling a manually triggered close, since no error event will follow to do it. [1]: https://github.com/odoo/odoo/pull/278075 runbot-944578 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#279046 Forward-Port-Of: odoo/odoo#278779
Description of the issue this commit addresses: The settlement tour expects an invoice named with the year 2026. On time-shifted test instances, invoices use a later year, so the tour cannot find the invoice and fails at the settlement selection step. --- Desired behavior after this commit is merged: This commit matches settlement invoices using the stable journal prefix, so the tour works regardless of the year in which it runs. --- runbot-[242206](https://runbot.odoo.com/odoo
Original PR description
Description of the issue this commit addresses: The settlement tour expects an invoice named with the year 2026. On time-shifted test instances, invoices use a later year, so the tour cannot find the invoice and fails at the settlement selection step. --- Desired behavior after this commit is merged: This commit matches settlement invoices using the stable journal prefix, so the tour works regardless of the year in which it runs. --- runbot-[242206](https://runbot.odoo.com/odoo/error/242206) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279756 Forward-Port-Of: odoo/odoo#278573
Forward-Port-Of: odoo/odoo#279378
Original PR description
Forward-Port-Of: odoo/odoo#279378
**Steps to reproduce:** - Install website_forum - Create a new post on the forum with the admin - Subscribe to the post notifications using the bell button - Create a new portal user and give him 5 karma (to give him enough rights to answer and comment) - Connect with the portal user and go to the post - Create an answer - Try to comment on your own answer - AccessError is raised **Issue:** Since [1] we check comodel access (in this case `res.partner`) when adding records. Here
Original PR description
**Steps to reproduce:** - Install website_forum - Create a new post on the forum with the admin - Subscribe to the post notifications using the bell button - Create a new portal user and give him 5…
**Steps to reproduce:**
- Install website_forum
- Create a new post on the forum with the admin
- Subscribe to the post notifications using the bell button
- Create a new portal user and give him 5 karma
(to give him enough rights to answer and comment)
- Connect with the portal user and go to the post
- Create an answer
- Try to comment on your own answer
- AccessError is raised
**Issue:**
Since [1] we check comodel access (in this case `res.partner`) when adding records. Here during the `message_post` the `question_followers` are added manually as `partner_ids` before sending (the logic only relies on the original post subscribers, not on the added comment/reply).
```py
question_followers = self.env['mail.followers'].sudo().search([
('res_model', '=', self._name),
('res_id', '=', self.parent_id.id),
('partner_id', '!=', False),
]).filtered(lambda fol: comment_subtype in fol.subtype_ids).mapped('partner_id')
partner_ids += question_followers.ids
```
As the portal user has no `read` access to the subscribers the message creation fails with a traceback.
**Fix:**
Add `sudo` to the `message_post` call of `post_comment`.
(Also fix a minor display issue in the 'Karma Error' notification)
[1] https://github.com/odoo/odoo/commit/aae732957c3c3b3590f5686cfccc0ab264d0b5c9
opw-5318757
Forward-Port-Of: odoo/odoo#279091
Forward-Port-Of: odoo/odoo#274751**PROBLEM** When creating a Credit Note from a Sale Order, the credit note lines uses the default account instead of using the return account set on the company. **STEP TO REPRODUCE** 1. Create a SO with a product. 2. Create an invoice and confirm it. 3. Return to the SO, and reduce the product qty (product invoice policy should be ordered qty for these steps). 4. Click again on create Invoice to create a Credit Note for the SO. 5. Notice the account on the product line is not the retur
Original PR description
**PROBLEM** When creating a Credit Note from a Sale Order, the credit note lines uses the default account instead of using the return account set on the company. **STEP TO REPRODUCE** 1. Create a SO with a product. 2. Create an invoice and confirm it. 3. Return to the SO, and reduce the product qty (product invoice policy should be ordered qty for these steps). 4. Click again on create Invoice to create a Credit Note for the SO. 5. Notice the account on the product line is not the return account. **CAUSE** In `_create_invoices()` on the SO model, we first create the moves as invoice, and then switch them to credit note if the total is negative. This means the lines are created with the invoice default account. opw-6266882 Forward-Port-Of: odoo/odoo#274354
**Issue** The package of the selected quant is not proposed as a destination package when adding stock move lines manually before the move line is saved. **Steps to reproduce** - Activate 'Packages' in the settings - Create a tracked product with package - Put 10 units in stock in package `P`. - Create and confirm a sale for 5 units - Open the delivery, make sure the quantity is set to 0 - Click 'Details' - "Add a line" and select the package P -> if you try to select a destination p
Original PR description
**Issue** The package of the selected quant is not proposed as a destination package when adding stock move lines manually before the move line is saved. **Steps to reproduce** - Activate 'Packages'…
**Issue** The package of the selected quant is not proposed as a destination package when adding stock move lines manually before the move line is saved. **Steps to reproduce** - Activate 'Packages' in the settings - Create a tracked product with package - Put 10 units in stock in package `P`. - Create and confirm a sale for 5 units - Open the delivery, make sure the quantity is set to 0 - Click 'Details' - "Add a line" and select the package P -> if you try to select a destination package, the package P is not proposed as it should - save it and reopen 'Details' -> if you try to select a destination package, the package P is now proposed **Cause** The domain of `result_package_id` (destination package) correctly includes `package_id`: https://github.com/odoo/odoo/blob/3a5f7431effd4b2b2eb8ce3eed81aaba42fcd8ea/addons/stock/models/stock_move_line.py#L52-L56 However, before saving, `package_id` is not yet populated into the new `stock.move.line` record. It will only be copied from `quant_id` by `_copy_quant_info()`: https://github.com/odoo/odoo/blob/3a5f7431effd4b2b2eb8ce3eed81aaba42fcd8ea/addons/stock/models/stock_move_line.py#L1016-L1025 which will only be called in the create method, while saving: https://github.com/odoo/odoo/blob/3a5f7431effd4b2b2eb8ce3eed81aaba42fcd8ea/addons/stock/models/stock_move_line.py#L350 opw-6370159 Forward-Port-Of: odoo/odoo#277797
Before this commit, the unread banner could stop showing in a channel until it was left and opened again: - open a channel with unread messages - click "Mark as Read" - read the same channel from another device - receive a new message: the server counter increases, still no banner This happens because an implicit mark as read freezes the local unread state, so the banner stays in place while the user reads. The problem is that it stays frozen even after the banner is gone, and never fol
Original PR description
Before this commit, the unread banner could stop showing in a channel until it was left and opened again: - open a channel with unread messages - click "Mark as Read" - read the same channel from another device - receive a new message: the server counter increases, still no banner This happens because an implicit mark as read freezes the local unread state, so the banner stays in place while the user reads. The problem is that it stays frozen even after the banner is gone, and never follows the server counter again. This commit freezes that state only while something is still unread locally. This also fixes the flaky test "no unread message banner after message is deleted". https://runbot.odoo.com/odoo/error/242776 Forward-Port-Of: odoo/odoo#279601 Forward-Port-Of: odoo/odoo#279195
Before this commit, the composer suggestion list could re-open right after the user closed it with Escape, and the next press of Escape would then close the list again instead of being handled by the composer (e.g. discarding a reply). This happened because NavigableList was re-opened on every patch: the useEffect opening the list had `[this.props]` as dependency, and props are a new object on every render. Any unrelated re-render of the composer (e.g. triggered by a late store update) would
Original PR description
Before this commit, the composer suggestion list could re-open right after the user closed it with Escape, and the next press of Escape would then close the list again instead of being handled by the composer (e.g. discarding a reply). This happened because NavigableList was re-opened on every patch: the useEffect opening the list had `[this.props]` as dependency, and props are a new object on every render. Any unrelated re-render of the composer (e.g. triggered by a late store update) would therefore re-open the list, which would then steal the next Escape from the composer. Fix by narrowing the dependency to the content of the options, so the list only opens on mount and when a new set of options arrives. https://runbot.odoo.com/odoo/error/944571 Forward-Port-Of: odoo/odoo#279275 Forward-Port-Of: odoo/odoo#278929
added tags for accounts and new demo data for l10n_cl_reports f29 refactor refactor file to company_demo.xml Add widthholding tax 2nd category for 2027 and 2028 since it is suitable for this report compatibility [FIX] l10n_cl: add more taxes and fix translation [FIX] l10n_cl: adapt fiscal position to new scheme. [FIX] l10n_cl: remove unused tags [FIX] l10n_cl: add fiscal position to taxes and replacement tax. Change refs in demo and fix demo values to make more consistent with real cases
Original PR description
added tags for accounts and new demo data for l10n_cl_reports f29 refactor refactor file to company_demo.xml Add widthholding tax 2nd category for 2027 and 2028 since it is suitable for this report compatibility [FIX] l10n_cl: add more taxes and fix translation [FIX] l10n_cl: adapt fiscal position to new scheme. [FIX] l10n_cl: remove unused tags [FIX] l10n_cl: add fiscal position to taxes and replacement tax. Change refs in demo and fix demo values to make more consistent with real cases [FIX] l10n_cl: change monthy taxes payable 210760 from payable to current [FIX] l10n_cl: add new ILA accounts to COA and fix ILA tax repartition lines Compatibility with 'remove tax_tag_invert' [FIX] l10n_cl: fix 'compras de combustibles' task-4329648 Forward-Port-Of: odoo/odoo#247545
**Steps to reproduce:** 1. Create a new SO and enable "Online Signature" and "Online Payment" in the "Other Info" tab 2. Click on Preview and click on "Sign & Pay" from the portal (demo payment should be enabled from the settings to proceed) 3. Once the transaction is processed and the order confirmed, check the confirmation email/PDF sent to the customer in the chatter **Issue:** - The order confirmation sent to the customer after paying online does not include the signature they provide
Original PR description
**Steps to reproduce:** 1. Create a new SO and enable "Online Signature" and "Online Payment" in the "Other Info" tab 2. Click on Preview and click on "Sign & Pay" from the portal (demo payment…
**Steps to reproduce:** 1. Create a new SO and enable "Online Signature" and "Online Payment" in the "Other Info" tab 2. Click on Preview and click on "Sign & Pay" from the portal (demo payment should be enabled from the settings to proceed) 3. Once the transaction is processed and the order confirmed, check the confirmation email/PDF sent to the customer in the chatter **Issue:** - The order confirmation sent to the customer after paying online does not include the signature they provided when accepting the quotation - Even if "Online Payment" is not enabled and Signing will directly confirm the order, the signature is still missing. **Why this happens:** - The signature block in `sale.report_saleorder_document` is gated by the `sale_include_signature` context key rather than solely by doc.signature. This was introduced by commit ef8246a4daf6146da2ed3cb78c37c7bf0937a4df to retain signature integrity. - `portal_quote_accept` only sets this context right after the customer signs on the pdf rendered for us (company), and was not passed through `_validate_order()` when there was no online payment - When online payment is required, `_has_to_be_paid()` defers the order confirmation which happens later, and the context is never set elsewhere **Fix:** - Pass the context when online payment is not required - If online payment is required, the sale quotation can be modified after being signed. However, since the customer previews the quotation when Paying, we can say the signature integrity is retained opw-6389733 Forward-Port-Of: odoo/odoo#278854
Current behavior before PR ----- The "unit cost" footer line was showing up on each page of the bom overview, overlapping with other lines. Desired behavior after PR is merged ----- The "unit cost" footer line should only appear at the bottom of the overview. Forward-Port-Of: odoo/odoo#262995
Original PR description
Current behavior before PR ----- The "unit cost" footer line was showing up on each page of the bom overview, overlapping with other lines. Desired behavior after PR is merged ----- The "unit cost" footer line should only appear at the bottom of the overview. Forward-Port-Of: odoo/odoo#262995
Make sure to click on the correct action menu when tryin to delete the selected website page. If we do not specify this we could randomly click on the little gear menu that do not contain the delete option. It's actually already done like this in 19.3 here https://github.com/odoo/odoo/blob/c5d7a6a90be4730e18070826a9394ab10dfc6be8/addons/website/static/tests/tours/page_manager.js#L129 runbot-233357 Forward-Port-Of: odoo/odoo#277605 Forward-Port-Of: odoo/odoo#276897
Original PR description
Make sure to click on the correct action menu when tryin to delete the selected website page. If we do not specify this we could randomly click on the little gear menu that do not contain the delete option. It's actually already done like this in 19.3 here https://github.com/odoo/odoo/blob/c5d7a6a90be4730e18070826a9394ab10dfc6be8/addons/website/static/tests/tours/page_manager.js#L129 runbot-233357 Forward-Port-Of: odoo/odoo#277605 Forward-Port-Of: odoo/odoo#276897
Steps to Reproduce the Error (Odoo SaaS 19.2): 1. Install l10n_gcc_invoice localization & Accounting 2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings > Configuration > Customer Invoices > Default Terms and Conditions 3. Create invoice with ar_001 partner 4. Confirm the invoice 5. Try to create credit note → Error: KeyError: 'en_US' Root Cause: The _load_narration_translation() workaround reads raw invoice_terms from DB and injects the entire JSONB di
Original PR description
Steps to Reproduce the Error (Odoo SaaS 19.2): 1. Install l10n_gcc_invoice localization & Accounting 2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings >…
Steps to Reproduce the Error (Odoo SaaS 19.2):
1. Install l10n_gcc_invoice localization & Accounting
2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings > Configuration > Customer Invoices > Default Terms and Conditions
3. Create invoice with ar_001 partner
4. Confirm the invoice
5. Try to create credit note → Error: KeyError: 'en_US'
Root Cause:
The _load_narration_translation() workaround reads raw invoice_terms from DB and injects the entire JSONB dict directly into cache, bypassing ORM field conversion. When Odoo 19.2's improved ORM conversion runs, it creates nested JSON in narration instead of a flat structure.
Timeline:
- bedf1cb66fbb: Workaround added to prevent T&C duplication in preview
- 75f050b9650d: Root cause fixed in report template (conditional display) → Made _load_narration_translation() redundant
- 4e4156536bc9: Odoo 19.2 improved ORM conversion → Now conflicts with the redundant workaround, causing nested JSON
How It Breaks:
1. Invoice creation: _load_narration_translation() injects raw dict into cache
2. ORM writes: nested JSON stored: {ar_001: {en_US: ., ar_001: Arabic}}
3. Credit note creation: copy_translations() expects flat structure → Crashes: KeyError: 'en_US'
Why It's Safe to Remove:
Report template already prevents T&C duplication (commit 75f050b9650d). Removing the workaround restores proper credit note creation without breaking T&C display.
Changes:
- Remove moves._load_narration_translation() in create()
- Remove out self.filtered('id')._load_narration_translation() in _compute_narration()
opw : 6284943
Forward-Port-Of: odoo/odoo#271037Steps to reproduce the issue easily: - Remove the section in the footer. - Drop enough snippets to have a scroll bar and to not see the footer when the scroll is at the top. - Drop the "Pricelist" snippet at the bottom of the page and click on a column. - Scroll up so the footer and the bottom of the snippet are not visible, and add a pricelist item with the "Add Product" option. - => The page scrolls to the new item, but a big white space appears at the bottom of the screen, as if we scrol
Original PR description
Steps to reproduce the issue easily: - Remove the section in the footer. - Drop enough snippets to have a scroll bar and to not see the footer when the scroll is at the top. - Drop the "Pricelist"…
Steps to reproduce the issue easily: - Remove the section in the footer. - Drop enough snippets to have a scroll bar and to not see the footer when the scroll is at the top. - Drop the "Pricelist" snippet at the bottom of the page and click on a column. - Scroll up so the footer and the bottom of the snippet are not visible, and add a pricelist item with the "Add Product" option. - => The page scrolls to the new item, but a big white space appears at the bottom of the screen, as if we scrolled too far. The same issue happens with similar steps in the following cases: - When using any option using the `addItem` action. - When undoing/redoing a step that was done in an element not in the viewport (the screen will scroll to it and we will have the issue). - When showing an invisible element (the screen will scroll to it if not in the viewport) - Adding a grid item with the "Add Elements" option. - Adding a new card in the "Floating Cards" snippet. The common point to all these cases is that they all scroll to the added or shown element with the `scrollIntoView` built-in function, which scrolls everything, including the viewport. It also doesn't take into account the header that changes during the scroll, often ending with the element hidden by the header. This commit fixes these issues by using the builder `scrollTo` util, which takes the header into account and only scrolls what needs to be. This function should always be preferred when scrolling in the builder. task-6314322 Forward-Port-Of: odoo/odoo#278897 Forward-Port-Of: odoo/odoo#275686
The amount in words split the total with int(decimal * 100), which truncates. 3989.33 is held in binary as 3989.3299..., so the kuruş/cents came out one short (32 instead of 33). The written amount then disagreed with the numeric total on the same invoice and Nilvera rejects it. Round to the currency precision and round the subunit instead. Task-6383690 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: ---
Original PR description
The amount in words split the total with int(decimal * 100), which truncates. 3989.33 is held in binary as 3989.3299..., so the kuruş/cents came out one short (32 instead of 33). The written amount then disagreed with the numeric total on the same invoice and Nilvera rejects it. Round to the currency precision and round the subunit instead. Task-6383690 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#277748 Forward-Port-Of: odoo/odoo#277180
**Problem:** When creating a new task, the Customer does not follow the project the user selects: once a first project has filled it, selecting another project keeps the previous project's customer. **Steps to reproduce:** 1. Create a new task and select a project that has a customer. 2. The Customer is set to that project's customer. 3. Select another project configured with a different customer. 4. Observe the Customer keeps the first project's customer. **Current behavior:** The C
Original PR description
**Problem:** When creating a new task, the Customer does not follow the project the user selects: once a first project has filled it, selecting another project keeps the previous project's customer.…
**Problem:** When creating a new task, the Customer does not follow the project the user selects: once a first project has filled it, selecting another project keeps the previous project's customer. **Steps to reproduce:** 1. Create a new task and select a project that has a customer. 2. The Customer is set to that project's customer. 3. Select another project configured with a different customer. 4. Observe the Customer keeps the first project's customer. **Current behavior:** The Customer keeps the first selected project's customer. **Expected behavior:** The Customer follows the selected project and shows its customer. **Cause of the issue:** partner_id is filled by _compute_partner_id, which only assigns a partner while the field is empty. Once a project has filled it, selecting another project no longer refreshes the now non-empty Customer. **Fix:** Refresh the Customer from the project on project_id change, but only while the task is new (no _origin). An existing task's customer is left untouched, since it may already carry sale order lines, timesheets, materials or worksheets that must not be reset when the project changes. opw-6315902 Forward-Port-Of: odoo/odoo#278526 Forward-Port-Of: odoo/odoo#276211
Steps to reproduce: 1. install mail 2. Send a voice message to anyone from the discuss app 3. Open the ui in mobile and see the voice messege duration Issue: - time is showing in two lines Solution: - Adjust the spacing of the voice player controls for small screens using responsive Bootstrap utility classes and prevent the duration text from shrinking, ensuring it remains on a single line while preserving the existing layout on larger screens. <table width="100%"> <tr> <th
Original PR description
Steps to reproduce:
1. install mail
2. Send a voice message to anyone from the discuss app
3. Open the ui in mobile and see the voice messege duration
Issue:
- time is showing in two lines
Solution:
- Adjust the spacing of the voice player controls for small screens using responsive Bootstrap utility classes and prevent the duration text from shrinking, ensuring it remains on a single line while preserving the existing layout on larger screens.
<table width="100%">
<tr>
<th>Before</th>
<th>After</th>
</tr>
<tr>
<td align="center">
<img alt="After" src="https://github.com/user-attachments/assets/98f41d1a-9082-4d5c-a34b-c9181e643e0a">
</td>
<td align="center">
<img alt="Before" src="https://github.com/user-attachments/assets/0f879988-b2e6-46c9-ba5a-0f935fde40ec">
</td>
</tr>
</table>
opw-6328609
Forward-Port-Of: odoo/odoo#271768Steps to reproduce: Use the real testing credentials Make sure the invoice sequence is not generated on the real testing credentials 1. Create an invoice with overseas partner 2. Create ewaybill Error from the portal: `[372] Invalid or Blank Consignee Ship-to State Code` It is currently a flaw in the government portal because in Government portal there is no option for the Other country (99) for Ship to state code and only option for Other Teritory(97) It is because in reality, i
Original PR description
Steps to reproduce: Use the real testing credentials Make sure the invoice sequence is not generated on the real testing credentials 1. Create an invoice with overseas partner 2. Create ewaybill…
Steps to reproduce: Use the real testing credentials Make sure the invoice sequence is not generated on the real testing credentials 1. Create an invoice with overseas partner 2. Create ewaybill Error from the portal: `[372] Invalid or Blank Consignee Ship-to State Code` It is currently a flaw in the government portal because in Government portal there is no option for the Other country (99) for Ship to state code and only option for Other Teritory(97) It is because in reality, it should the port ship to state code but there cases where goods can be transfered to nearby country i.e. Bangladesh, Nepal where good can taken by road from India In that case the state code should be 97 task-6431082 **Second Commit** - [FIX] l10n_in_ewaybill: import/export GSTIN should be URP Steps to reproduce: Use the real testing credentials Create a SEZ partner Create an invoice and ewaybill Select the type of Ewaybill as Export Tax Invoice We get error code-450 which clearly states, `450 For outward-export ewaybill, To GSTIN has to be either URP or SEZ` --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279289
Issue: --- Adding a rating with a message on website is causing TB as the portal user doesn't have the access to send rating message. opw-6316142 Forward-Port-Of: odoo/odoo#279539 Forward-Port-Of: odoo/odoo#271833
Original PR description
Issue: --- Adding a rating with a message on website is causing TB as the portal user doesn't have the access to send rating message. opw-6316142 Forward-Port-Of: odoo/odoo#279539 Forward-Port-Of: odoo/odoo#271833
17 changes
Enhancements to existing features
Steps to reproduce: 1. Create a sales order. 2. Confirm or cancel the order. 3. Share the quotation link. 4. Open the quotation from an incognito window or the customer portal. Issue: - A 'Quotation Viewed by Customer' notification is sent even though the document is no longer an active quotation. Fix: - Only send the notification while the order is in quotation or quotation sent state. opw-6419364 Forward-Port-Of: odoo/odoo#278633
Original PR description
Steps to reproduce: 1. Create a sales order. 2. Confirm or cancel the order. 3. Share the quotation link. 4. Open the quotation from an incognito window or the customer portal. Issue: - A 'Quotation Viewed by Customer' notification is sent even though the document is no longer an active quotation. Fix: - Only send the notification while the order is in quotation or quotation sent state. opw-6419364 Forward-Port-Of: odoo/odoo#278633
Resolved issues and error corrections
### Steps to reproduce: - Install `sale_mrp` and `l10n_ke_edi_oscu_stock` - Set company country to be 'Kenya' - Run the `test_kit_cogs_entry_with_delivery_line_removal` test > odoo.exceptions.UserError: Cannot create an invoice. No items are available to invoice. ### Cause of Issue: The test validates COGS entries for a kit by creating a sale order, then generating an invoice. When `l10n_ke_edi_oscu_stock` is installed, it overrides the `invoice_policy` of all storable products for Ke
Original PR description
### Steps to reproduce: - Install `sale_mrp` and `l10n_ke_edi_oscu_stock` - Set company country to be 'Kenya' - Run the `test_kit_cogs_entry_with_delivery_line_removal` test >…
### Steps to reproduce: - Install `sale_mrp` and `l10n_ke_edi_oscu_stock` - Set company country to be 'Kenya' - Run the `test_kit_cogs_entry_with_delivery_line_removal` test > odoo.exceptions.UserError: Cannot create an invoice. No items are available to invoice. ### Cause of Issue: The test validates COGS entries for a kit by creating a sale order, then generating an invoice. When `l10n_ke_edi_oscu_stock` is installed, it overrides the `invoice_policy` of all storable products for Kenyan companies to `'delivery'`. https://github.com/odoo/enterprise/blob/82b736a283ed5ab3ad431a1cdbcedc1b8e3c2d7c/l10n_ke_edi_oscu_stock/models/product.py#L16-L21 Because the test removes a required component from the picking, the delivered quantity of the kit is computed as 0. Since the kit's invoice policy is dynamically forced to `'delivery'` by the localization, calling `_create_invoices()` raises a `UserError` as there are no delivered items to invoice, failing the test on runbot. ### Fix: Ensure that kit product use an invoicing policy of 'Ordered Quantities' rather than the default 'Delivered Quantities'. This allows the test to proceed and correctly evaluate the core COGS computation logic it was designed to check. runbot-243342
Steps to produce: --- - Install the Sales module. - Enable `Pricelists` from Sales settings. - Create a new product. - Go to Sales > Products > Pricelists and open an existing pricelist. - Add the following rules for a product: - min qty: 1 > price: 100 - min qty:10 > price: 80 - Create a new quotation > add section > add the same product. - Set the section as optional > Preview the quotation. - Change its quantity to 10. Added test covering the fix introduced in [com
Original PR description
Steps to produce:
---
- Install the Sales module.
- Enable `Pricelists` from Sales settings.
- Create a new product.
- Go to Sales > Products > Pricelists and open an existing pricelist.
- Add the following rules for a product:
- min qty: 1 > price: 100
- min qty:10 > price: 80
- Create a new quotation > add section > add the same product.
- Set the section as optional > Preview the quotation.
- Change its quantity to 10.
Added test covering the fix introduced in [commit], ensuring
that pricelist rules are correctly reapplied when the quantity of an
optional product is changed from the quotation preview.
[commit]: https://github.com/odoo/odoo/commit/93b6bdd6a4909bc0b45b90ab6a2d0734a218292d
opw-6241183
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#279135
Forward-Port-Of: odoo/odoo#266597The `bus_monitoring_service` test "connection considered as lost after failed reconnect attempt" fails about half of the time. Since [1], the reconnect delay in tests is much smaller. The retry therefore fires while the mock socket is still in the closing state. `_start` detects that socket and triggers the close event manually to keep the lifecycle consistent. In other cases, the error event will schedule a reconnect but in this case it will never arrive. The worker is then left with n
Original PR description
The `bus_monitoring_service` test "connection considered as lost after failed reconnect attempt" fails about half of the time. Since [1], the reconnect delay in tests is much smaller. The retry…
The `bus_monitoring_service` test "connection considered as lost after failed reconnect attempt" fails about half of the time. Since [1], the reconnect delay in tests is much smaller. The retry therefore fires while the mock socket is still in the closing state. `_start` detects that socket and triggers the close event manually to keep the lifecycle consistent. In other cases, the error event will schedule a reconnect but in this case it will never arrive. The worker is then left with no socket, no listeners and no pending timeout: it never reconnects. Schedule the reconnection when handling a manually triggered close, since no error event will follow to do it. [1]: https://github.com/odoo/odoo/pull/278075 runbot-944578 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#279046 Forward-Port-Of: odoo/odoo#278779
to reproduce: ============= - Have a database with a large number of kit BoMs (e.g. ~160k phantom mrp.bom records). - Open Inventory Valuation. - The request never returns and hangs forever. problem: ======== Commit 11e9c1297439 started searching the valued products with `('qty_available', '!=', 0)`. On `product.product` this triggers the mrp override `_search_qty_available_new`, which loads every phantom BoM in the database and computes `qty_available` (via BoM explode) for each
Original PR description
to reproduce: ============= - Have a database with a large number of kit BoMs (e.g. ~160k phantom mrp.bom records). - Open Inventory Valuation. - The request never returns and hangs forever. problem:…
to reproduce:
=============
- Have a database with a large number of kit BoMs (e.g. ~160k phantom
mrp.bom records).
- Open Inventory Valuation.
- The request never returns and hangs forever.
problem:
========
Commit 11e9c1297439 started searching the valued products with
`('qty_available', '!=', 0)`. On `product.product` this triggers the mrp
override `_search_qty_available_new`, which loads every phantom BoM in the
database and computes `qty_available` (via BoM explode) for each kit. On top
of that, the override builds the kit products recordset with repeated
`kit_products |= ...` unions, which is O(n^2). With a large catalog of kits
the combination of O(n) heavy explodes and O(n^2) unions never returns.
On top of the performance issue, the new search dropped the kit exclusion
that `_get_accounts_by_product` previously applied through
`_get_valuation_product_domain` (`('is_kits', '=', False)` in mrp_account),
so phantom products - which are never valued on their own - were wrongly
pulled into the valuation.
solution:
=========
Restore the kit exclusion: search the valued products through
`_get_valuation_product_domain()` (which adds `('is_kits', '=', False)` in
mrp_account) instead of the ad-hoc `('is_storable', '=', True)` domain, so
phantom products are no longer valued.
Add a `skip_kit_qty_available` context key on `_search_qty_available_new` so
callers that intentionally exclude kits can skip the costly kit BoM expansion
and return the base (quant-based) result directly. The key is set in
mrp_account (via `_get_valuation_product_context`), alongside the domain that
already excludes kits, so the optimization and its precondition stay in the
same layer.
Also make the remaining kit path in `_search_qty_available_new` scale: build
the kit products recordset in a single pass instead of O(n^2) recordset
unions, and use a set for membership checks.
Benchmark:
==========
for `_get_report_data()` (averaged over 5 runs):
| # Input data (phantom kits) | Before PR | After PR |
| :---: | :---: | :---: |
| 1,000 | 2.558 s | 35.5 ms |
| 5,000 | 10.991 s | 41.6 ms |
| 10,000 | 20.869 s | 66.0 ms |
| 25,000 | 61.807 s | 80.7 ms |
| 50,000 | 195.382 s | 87.9 ms |
the improvement is **~99% faster**
opw-6312168
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#273982When a PoS runs in a currency other than the company currency, product prices are loaded already converted to the PoS currency (`list_price`, `lst_price`, `standard_price` all go through `_convert_pos_data_currency`). The prices carried by combos were not: `product.combo.base_price` is computed in the combo currency (the company currency) and `product.combo.item.extra_price` is stored in the product currency, but neither was converted when loaded in the PoS. As a result, a product priced at 2
Original PR description
When a PoS runs in a currency other than the company currency, product prices are loaded already converted to the PoS currency (`list_price`, `lst_price`, `standard_price` all go through…
When a PoS runs in a currency other than the company currency, product prices are loaded already converted to the PoS currency (`list_price`, `lst_price`, `standard_price` all go through `_convert_pos_data_currency`). The prices carried by combos were not: `product.combo.base_price` is computed in the combo currency (the company currency) and `product.combo.item.extra_price` is stored in the product currency, but neither was converted when loaded in the PoS. As a result, a product priced at 2 USD (= 80 ZIG) was correctly shown as 80 ZIG on its own, yet appeared as 2 ZIG once it was part of a combo, since the raw amount was displayed as-is in the PoS currency. Convert `base_price` and `extra_price` from each record's own `currency_id` to the PoS currency at load time, mirroring what is already done for product prices. Steps to reproduce: - Set a product to 2 USD and a PoS to a ZIG pricelist (rate 40). - Open the PoS: the standalone product shows 80 ZIG. - Add the same product as a combo item: it shows 2 ZIG instead of 80 ZIG. opw-6410243 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279253 Forward-Port-Of: odoo/odoo#278330
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
When an order from a closed session is invoiced, a misc reversal move is created to "extract" the order from the session closing entry. When the PoS config uses a currency different from the company currency, posting that reversal move could fail with "The entry is not balanced.", making it impossible to invoice the order. Steps to reproduce: - company in currency A, PoS config in currency B, with a conversion rate producing rounding drift (e.g. 0.4007) - sell a product of 20.0 B + 15% t
Original PR description
When an order from a closed session is invoiced, a misc reversal move is created to "extract" the order from the session closing entry. When the PoS config uses a currency different from the company…
When an order from a closed session is invoiced, a misc reversal move is created to "extract" the order from the session closing entry. When the PoS config uses a currency different from the company currency, posting that reversal move could fail with "The entry is not balanced.", making it impossible to invoice the order. Steps to reproduce: - company in currency A, PoS config in currency B, with a conversion rate producing rounding drift (e.g. 0.4007) - sell a product of 20.0 B + 15% tax (23.0 B), paid by bank, without invoicing - close the session - set a partner on the order and invoice it => UserError: "The entry is not balanced." Cause: in `_prepare_aml_values_list_per_nature`, the product and tax lines each get their balance converted and rounded individually (20.0 * 0.4007 -> 8.01, 3.0 * 0.4007 -> 1.20), while the payment term line was converted from the payment total, without rounding (23.0 * 0.4007 -> 9.2161). Per-line rounding does not distribute over the sum, so the balances could differ by a few cents (8.01 + 1.20 != 9.22) and the move could not be posted. The closing entry has the balancing-account wizard as an escape valve for such differences; the reversal move had none. Fix, following what is done for regular invoices (see `account.move._compute_needed_terms`, where the payment term balance is derived from the sum of the already rounded lines): - round the payment term conversions - put the conversion residual on the last payment term line so the payment terms exactly counterbalance the other lines, but only when the amounts in currency are balanced, so it can only absorb rounding drift - include the cash rounding amounts in the accumulated totals - fix the swapped `amount_currency`/`balance` values when merging two non-split payments on the same receivable account opw-6375309 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275673
### Issue before this commit: When importing an electronic invoice from SDI that is failing with an exception, the resulting account.move record was saved in the "Miscellaneous Operations" journal instead of the correct one (Vendor Bills), even though the move_type itself was correct. ### Steps to reproduce the issue: Pre steps: you need to have access to https://iap-services-test.odoo.com/odoo 1. Download Accounting and l10n_it 2. Go to Settings > Companies and set the VAT of IT company
Original PR description
### Issue before this commit: When importing an electronic invoice from SDI that is failing with an exception, the resulting account.move record was saved in the "Miscellaneous Operations" journal…
### Issue before this commit: When importing an electronic invoice from SDI that is failing with an exception, the resulting account.move record was saved in the "Miscellaneous Operations" journal instead of the correct one (Vendor Bills), even though the move_type itself was correct. ### Steps to reproduce the issue: Pre steps: you need to have access to https://iap-services-test.odoo.com/odoo 1. Download Accounting and l10n_it 2. Go to Settings > Companies and set the VAT of IT company the same as the one in the xml 3. Go to Settings > Italian Electronic Invoicing and select Test 4. Go into the code and insert an Exception inside the function _l10n_it_edi_import_invoice after self.move_type = move_type (or create any type of exception from the user interface) 5. Go to IAP service into IT EDI app and see that your company is there as user 6. Click into the record > receive move button > upload your xml > create 7. Go to your DB > Scheduled Actions > filter with IT > IT EDI: Receive invoices from the SdI > Run Manually 8. Go to Journal entries, remove the filter and find your imported bill 9. You can see it was inserted into the Miscellaneous Operations Journal instead of a Vendor Bill Journal ### Cause of the issue: The move is created inside a savepoint context manager, designed so that even if parsing fails, an empty move with the attachment still remains. The problem is that if the exception is raised, the savepoint rollback undoes everything that follows, but the journal was already determined before the correct move_type was known, leaving the move in the wrong default journal. ### Reason to introduce the fix: The fix is needed to ensure that, regardless of where parsing fails, the move's journal is correctly set even if an exception occurs so that it is possible to find the move in the correct section even if not imported correctly. opw-6397712 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279566 Forward-Port-Of: odoo/odoo#278111
Steps to reproduce the bug: - Install point_of_sale - Open the POS frontend and create a new product from the register - Add it to the order, then open its product info popup and edit it - Rename it and change its price - Confirm the edit dialog - Click on the (renamed) product again to add it to the order Problem: On runbot the tour test_product_create_update_from_frontend (point_of_sale/tests/test_frontend.py, MobileTestUi) intermittently times out waiting for the orderline to sh
Original PR description
Steps to reproduce the bug: - Install point_of_sale - Open the POS frontend and create a new product from the register - Add it to the order, then open its product info popup and edit it - Rename it…
Steps to reproduce the bug:
- Install point_of_sale
- Open the POS frontend and create a new product from the register
- Add it to the order, then open its product info popup and edit it
- Rename it and change its price
- Confirm the edit dialog
- Click on the (renamed) product again to add it to the order
Problem:
On runbot the tour test_product_create_update_from_frontend (point_of_sale/tests/test_frontend.py, MobileTestUi) intermittently times out waiting for the orderline to show the edited product name/quantity/ price combination.
editProduct()'s onSave callback in pos_store.js closed the edit dialog via act_window_close right after firing this.data.read("product.template", ...) and this.data.searchRead("product.product", ...), without waiting for either call to resolve. When the dialog closes before those RPCs land, the in-memory product record used by canBeMergedWith() (pos_order_line.js) to decide how to merge/create the next orderline can still hold the stale price, so re-clicking the product right after editing produces an orderline that never matches the expected quantity/price.
Solution:
Make onSave async and await both this.data.read() and this.data.searchRead() before closing the dialog, so the reactive store is guaranteed to hold the updated product data before the user (or the tour) can interact with the product again.
runbot-223630
Forward-Port-Of: odoo/odoo#279496
Forward-Port-Of: odoo/odoo#277698added tags for accounts and new demo data for l10n_cl_reports f29 refactor refactor file to company_demo.xml Add widthholding tax 2nd category for 2027 and 2028 since it is suitable for this report compatibility [FIX] l10n_cl: add more taxes and fix translation [FIX] l10n_cl: adapt fiscal position to new scheme. [FIX] l10n_cl: remove unused tags [FIX] l10n_cl: add fiscal position to taxes and replacement tax. Change refs in demo and fix demo values to make more consistent with real cases
Original PR description
added tags for accounts and new demo data for l10n_cl_reports f29 refactor refactor file to company_demo.xml Add widthholding tax 2nd category for 2027 and 2028 since it is suitable for this report compatibility [FIX] l10n_cl: add more taxes and fix translation [FIX] l10n_cl: adapt fiscal position to new scheme. [FIX] l10n_cl: remove unused tags [FIX] l10n_cl: add fiscal position to taxes and replacement tax. Change refs in demo and fix demo values to make more consistent with real cases [FIX] l10n_cl: change monthy taxes payable 210760 from payable to current [FIX] l10n_cl: add new ILA accounts to COA and fix ILA tax repartition lines Compatibility with 'remove tax_tag_invert' [FIX] l10n_cl: fix 'compras de combustibles' task-4329648 Forward-Port-Of: odoo/odoo#247545
**Steps to reproduce:** 1. Create a new SO and enable "Online Signature" and "Online Payment" in the "Other Info" tab 2. Click on Preview and click on "Sign & Pay" from the portal (demo payment should be enabled from the settings to proceed) 3. Once the transaction is processed and the order confirmed, check the confirmation email/PDF sent to the customer in the chatter **Issue:** - The order confirmation sent to the customer after paying online does not include the signature they provide
Original PR description
**Steps to reproduce:** 1. Create a new SO and enable "Online Signature" and "Online Payment" in the "Other Info" tab 2. Click on Preview and click on "Sign & Pay" from the portal (demo payment…
**Steps to reproduce:** 1. Create a new SO and enable "Online Signature" and "Online Payment" in the "Other Info" tab 2. Click on Preview and click on "Sign & Pay" from the portal (demo payment should be enabled from the settings to proceed) 3. Once the transaction is processed and the order confirmed, check the confirmation email/PDF sent to the customer in the chatter **Issue:** - The order confirmation sent to the customer after paying online does not include the signature they provided when accepting the quotation - Even if "Online Payment" is not enabled and Signing will directly confirm the order, the signature is still missing. **Why this happens:** - The signature block in `sale.report_saleorder_document` is gated by the `sale_include_signature` context key rather than solely by doc.signature. This was introduced by commit ef8246a4daf6146da2ed3cb78c37c7bf0937a4df to retain signature integrity. - `portal_quote_accept` only sets this context right after the customer signs on the pdf rendered for us (company), and was not passed through `_validate_order()` when there was no online payment - When online payment is required, `_has_to_be_paid()` defers the order confirmation which happens later, and the context is never set elsewhere **Fix:** - Pass the context when online payment is not required - If online payment is required, the sale quotation can be modified after being signed. However, since the customer previews the quotation when Paying, we can say the signature integrity is retained opw-6389733 Forward-Port-Of: odoo/odoo#278854
**PROBLEM** When creating a Credit Note from a Sale Order, the credit note lines uses the default account instead of using the return account set on the company. **STEP TO REPRODUCE** 1. Create a SO with a product. 2. Create an invoice and confirm it. 3. Return to the SO, and reduce the product qty (product invoice policy should be ordered qty for these steps). 4. Click again on create Invoice to create a Credit Note for the SO. 5. Notice the account on the product line is not the retur
Original PR description
**PROBLEM** When creating a Credit Note from a Sale Order, the credit note lines uses the default account instead of using the return account set on the company. **STEP TO REPRODUCE** 1. Create a SO with a product. 2. Create an invoice and confirm it. 3. Return to the SO, and reduce the product qty (product invoice policy should be ordered qty for these steps). 4. Click again on create Invoice to create a Credit Note for the SO. 5. Notice the account on the product line is not the return account. **CAUSE** In `_create_invoices()` on the SO model, we first create the moves as invoice, and then switch them to credit note if the total is negative. This means the lines are created with the invoice default account. opw-6266882 Forward-Port-Of: odoo/odoo#274354
When a product with no attributes is sold, the description_picking field of the stock.move is empty. Steps to reproduce: ------------------- * Create a product with no attributes * Create a sale order with this product * Confirm the sale order > Observation: The description_picking field of the stock.move is empty The issue was originally reported because the e-Waybill in India had an empty description for the product. Why the fix: ------------ When trying to avoid duplicating th
Original PR description
When a product with no attributes is sold, the description_picking field of the stock.move is empty. Steps to reproduce: ------------------- * Create a product with no attributes * Create a sale order with this product * Confirm the sale order > Observation: The description_picking field of the stock.move is empty The issue was originally reported because the e-Waybill in India had an empty description for the product. Why the fix: ------------ When trying to avoid duplicating the product name, we should first check that it would not result in an empty description picking. opw-6318785 Forward-Port-Of: odoo/odoo#275248
Steps to Reproduce the Error (Odoo SaaS 19.2): 1. Install l10n_gcc_invoice localization & Accounting 2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings > Configuration > Customer Invoices > Default Terms and Conditions 3. Create invoice with ar_001 partner 4. Confirm the invoice 5. Try to create credit note → Error: KeyError: 'en_US' Root Cause: The _load_narration_translation() workaround reads raw invoice_terms from DB and injects the entire JSONB di
Original PR description
Steps to Reproduce the Error (Odoo SaaS 19.2): 1. Install l10n_gcc_invoice localization & Accounting 2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings >…
Steps to Reproduce the Error (Odoo SaaS 19.2):
1. Install l10n_gcc_invoice localization & Accounting
2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings > Configuration > Customer Invoices > Default Terms and Conditions
3. Create invoice with ar_001 partner
4. Confirm the invoice
5. Try to create credit note → Error: KeyError: 'en_US'
Root Cause:
The _load_narration_translation() workaround reads raw invoice_terms from DB and injects the entire JSONB dict directly into cache, bypassing ORM field conversion. When Odoo 19.2's improved ORM conversion runs, it creates nested JSON in narration instead of a flat structure.
Timeline:
- bedf1cb66fbb: Workaround added to prevent T&C duplication in preview
- 75f050b9650d: Root cause fixed in report template (conditional display) → Made _load_narration_translation() redundant
- 4e4156536bc9: Odoo 19.2 improved ORM conversion → Now conflicts with the redundant workaround, causing nested JSON
How It Breaks:
1. Invoice creation: _load_narration_translation() injects raw dict into cache
2. ORM writes: nested JSON stored: {ar_001: {en_US: ., ar_001: Arabic}}
3. Credit note creation: copy_translations() expects flat structure → Crashes: KeyError: 'en_US'
Why It's Safe to Remove:
Report template already prevents T&C duplication (commit 75f050b9650d). Removing the workaround restores proper credit note creation without breaking T&C display.
Changes:
- Remove moves._load_narration_translation() in create()
- Remove out self.filtered('id')._load_narration_translation() in _compute_narration()
opw : 6284943
Forward-Port-Of: odoo/odoo#271037This update resolves an issue where the 'Contact Us' button on product pages wasn't correctly redirecting to snippets, specifically when a zero-price product was involved. The fix ensures that the button functions as intended, directing users to the desired snippet destination.
Original PR description
Issue: ------- When a zero price product is created and the contact us button on the product page is intended to redirect to some snippets created through drag and drop then the button doesn't work…
Issue: ------- When a zero price product is created and the contact us button on the product page is intended to redirect to some snippets created through drag and drop then the button doesn't work as intended meaning it doesn't redirects to the desired snippet even after putting the correct anchor. for ex: `#snippet-anchor` in the `Button URL` field in the settings. Cause: -------- This works fine for the pages having '/contactus' or '/'. Issues raise only when we try to redirect to a snippet. Now, if the we try to redirect to any snippet on click of the button(Contact Us) by placing the corresponding anchor, it will not redirect/work as intended. This is because of the appending`?subject=product_name` that took place. Solution: ------------ To concatenate the `subject=product_name` conditionally if the url has '#' in it If yes, we just use the `url` in the URL so that it redirects as intended else concatenate the subject & so on. This is because for redirecting to snippets we use anchors such as '#Let's-Connect'. So, In an anchor the '#' will definitely reside. Steps to reproduce: ----------------------- 1. Create a db in version 18.3 with website_sale installed. 2. Enable the `Prevent Sale of Zero Priced Product` checkbox in the settings. 3. Create a zero price product and few snippets under it and copy the anchor of one of the snippets to redirect when clicked on the 'Contact Us' button. 4. Use the Anchor(for ex: '#Let's-Connect') in the 'Button URL' field of settings. 5. Navigate to the created product and click on the 'Contact Us' button. Nothing happens & no intended redirection to the desired snippet. Ref PR: ---------- https://github.com/odoo/odoo/pull/189049/changes#diff-39e02d03a8b765b4e3afc68627aeb33f11b587163638fedfb92ed5657c3336e7R398-R399 Attachments: ----------------- **Before Fix:** [vokoscreenNG-2026-02-06_17-36-37.webm](https://github.com/user-attachments/assets/a09101d4-13df-415d-a902-420a28aedef0) **After Fix**: [vokoscreenNG-2026-02-06_17-38-37.webm](https://github.com/user-attachments/assets/a6256d0f-d8cb-4146-b95e-33452a0a79c5) - OPW - [5494517](https://www.odoo.com/odoo/project/70/tasks/5494517) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#249906 Forward-Port-Of: odoo/odoo#247587
Miscellaneous changes
When generating the Sales Report or Session Report with a large number of orders (1000+), the report computation could take several minutes or fail entirely with cursor closed errors. This was mainly caused by multiple inefficient ORM patterns, such as repeated searches inside nested loops and unnecessary recordset instantiations. This commit optimizes the report generation logic by: - Avoiding repeated searches inside loops (e.g. account payments per session) - Using `_search` instead of `
Original PR description
When generating the Sales Report or Session Report with a large number of orders (1000+), the report computation could take several minutes or fail entirely with cursor closed errors. This was mainly…
When generating the Sales Report or Session Report with a large number of orders (1000+), the report computation could take several minutes or fail entirely with cursor closed errors. This was mainly caused by multiple inefficient ORM patterns, such as repeated searches inside nested loops and unnecessary recordset instantiations. This commit optimizes the report generation logic by: - Avoiding repeated searches inside loops (e.g. account payments per session) - Using `_search` instead of `search` where only record ids are required - Grouping and caching session-related records (payments, moves, cash moves) - Reducing redundant ORM calls and Python-level iterations - Preserving the exact report output structure and values The returned data remains unchanged; only record ordering may differ due to optimized iteration and grouping. As a result, report generation time is significantly reduced and the report can be generated reliably even with very large order counts. task-5452734 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278843 Forward-Port-Of: odoo/odoo#241828
16 changes
Enhancements to existing features
Steps to reproduce: 1. Create a sales order. 2. Confirm or cancel the order. 3. Share the quotation link. 4. Open the quotation from an incognito window or the customer portal. Issue: - A 'Quotation Viewed by Customer' notification is sent even though the document is no longer an active quotation. Fix: - Only send the notification while the order is in quotation or quotation sent state. opw-6419364 Forward-Port-Of: odoo/odoo#278633
Original PR description
Steps to reproduce: 1. Create a sales order. 2. Confirm or cancel the order. 3. Share the quotation link. 4. Open the quotation from an incognito window or the customer portal. Issue: - A 'Quotation Viewed by Customer' notification is sent even though the document is no longer an active quotation. Fix: - Only send the notification while the order is in quotation or quotation sent state. opw-6419364 Forward-Port-Of: odoo/odoo#278633
Resolved issues and error corrections
When an order from a closed session is invoiced, a misc reversal move is created to "extract" the order from the session closing entry. When the PoS config uses a currency different from the company currency, posting that reversal move could fail with "The entry is not balanced.", making it impossible to invoice the order. Steps to reproduce: - company in currency A, PoS config in currency B, with a conversion rate producing rounding drift (e.g. 0.4007) - sell a product of 20.0 B + 15% t
Original PR description
When an order from a closed session is invoiced, a misc reversal move is created to "extract" the order from the session closing entry. When the PoS config uses a currency different from the company…
When an order from a closed session is invoiced, a misc reversal move is created to "extract" the order from the session closing entry. When the PoS config uses a currency different from the company currency, posting that reversal move could fail with "The entry is not balanced.", making it impossible to invoice the order. Steps to reproduce: - company in currency A, PoS config in currency B, with a conversion rate producing rounding drift (e.g. 0.4007) - sell a product of 20.0 B + 15% tax (23.0 B), paid by bank, without invoicing - close the session - set a partner on the order and invoice it => UserError: "The entry is not balanced." Cause: in `_prepare_aml_values_list_per_nature`, the product and tax lines each get their balance converted and rounded individually (20.0 * 0.4007 -> 8.01, 3.0 * 0.4007 -> 1.20), while the payment term line was converted from the payment total, without rounding (23.0 * 0.4007 -> 9.2161). Per-line rounding does not distribute over the sum, so the balances could differ by a few cents (8.01 + 1.20 != 9.22) and the move could not be posted. The closing entry has the balancing-account wizard as an escape valve for such differences; the reversal move had none. Fix, following what is done for regular invoices (see `account.move._compute_needed_terms`, where the payment term balance is derived from the sum of the already rounded lines): - round the payment term conversions - put the conversion residual on the last payment term line so the payment terms exactly counterbalance the other lines, but only when the amounts in currency are balanced, so it can only absorb rounding drift - include the cash rounding amounts in the accumulated totals - fix the swapped `amount_currency`/`balance` values when merging two non-split payments on the same receivable account opw-6375309 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275673
### Issue: When a `stock.move.line` is manually added to a component move of a Manufacturing Order via the debug View button, it is not linked to the MO This causes the line to appear without a `production_id` in Move History (shown in gray in 18.3+ instead of colored) ### Cause: `production_id` is set on move lines in `_action_assign`, overridden in `mrp` to propagate MO-specific data: https://github.com/odoo/odoo/blob/e8d4ea2dc71109e9afc5b894c9359bcfc08295ae/addons/mrp/models/stock_mov
Original PR description
### Issue: When a `stock.move.line` is manually added to a component move of a Manufacturing Order via the debug View button, it is not linked to the MO This causes the line to appear without a…
### Issue: When a `stock.move.line` is manually added to a component move of a Manufacturing Order via the debug View button, it is not linked to the MO This causes the line to appear without a `production_id` in Move History (shown in gray in 18.3+ instead of colored) ### Cause: `production_id` is set on move lines in `_action_assign`, overridden in `mrp` to propagate MO-specific data: https://github.com/odoo/odoo/blob/e8d4ea2dc71109e9afc5b894c9359bcfc08295ae/addons/mrp/models/stock_move.py#L352-L358 In the normal flow, `_action_assign` is called by `_action_confirm` on the `stock.move`: https://github.com/odoo/odoo/blob/737e28b9c8609d488d93ce7ce05941ff93779e04/addons/stock/models/stock_move.py#L1644-L1646 But when a line is added manually, the move is already created with state `assigned`, so `_action_confirm` skips the call and `_action_assign` is never executed ### Fix: Setting `production_id` in `_action_assign` was incorrectly placed — there is no reason to set it during move assignment Moving it to the move line creation avoids the issue entirely and removes the dependency on a code path that may not be triggered ### Steps to reproduce: - Install `mrp` - Create a BoM for a tracked product with 2 tracked components - Enable Developer mode - Create a Manufacturing Order for the product - Unhide the View button on a component move and click it - Add a new line for the first component (qty: 1) - Confirm and Produce All the MO - Go to Inventory > Reporting > Move History - Add `production_id` via Studio (or check line color in 18.3+) Before the fix, the manually added line has no `production_id` (and in 18.3+ the line is gray instead of colored) opw-6250911 Forward-Port-Of: odoo/odoo#272035
**Issue** The height is not correctly computed in the picking form when editing product description. **Steps to reproduce** - Create a delivery for a product - Add a description to it - Click on editing the description -> Observe that the description is partially hidden because the widget height is incorrectly computed **Cause** Since commit https://github.com/odoo/odoo/commit/e4f4171e1bc838840c0bd6111cd78f348b201ac2, `useProductAndLabelAutoresize` no longer assigns a height to the
Original PR description
**Issue** The height is not correctly computed in the picking form when editing product description. **Steps to reproduce** - Create a delivery for a product - Add a description to it - Click on…
**Issue** The height is not correctly computed in the picking form when editing product description. **Steps to reproduce** - Create a delivery for a product - Add a description to it - Click on editing the description -> Observe that the description is partially hidden because the widget height is incorrectly computed **Cause** Since commit https://github.com/odoo/odoo/commit/e4f4171e1bc838840c0bd6111cd78f348b201ac2, `useProductAndLabelAutoresize` no longer assigns a height to the widget root. The corresponding widget is `MoveProductLabelField`, which extends `ProductNameAndDescriptionField`: https://github.com/odoo/odoo/blob/91b59f285248c120fe9e3e5f6b6f086ea7be2837/addons/stock/static/src/views/picking_form/stock_move_product_label.js#L5 It uses `useProductAndLabelAutoresize`: https://github.com/odoo/odoo/blob/91b59f285248c120fe9e3e5f6b6f086ea7be2837/addons/product/static/src/product_name_and_description/product_name_and_description.js#L54-L56 **Solution** Explicitly add a div around the product display and description to still use the `Autoresize` Forward-Port-Of: odoo/odoo#271564
The amount in words split the total with int(decimal * 100), which truncates. 3989.33 is held in binary as 3989.3299..., so the kuruş/cents came out one short (32 instead of 33). The written amount then disagreed with the numeric total on the same invoice and Nilvera rejects it. Round to the currency precision and round the subunit instead. Task-6383690 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: ---
Original PR description
The amount in words split the total with int(decimal * 100), which truncates. 3989.33 is held in binary as 3989.3299..., so the kuruş/cents came out one short (32 instead of 33). The written amount then disagreed with the numeric total on the same invoice and Nilvera rejects it. Round to the currency precision and round the subunit instead. Task-6383690 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#277748 Forward-Port-Of: odoo/odoo#277180
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
Steps to reproduce the bug: - Install point_of_sale - Open the POS frontend and create a new product from the register - Add it to the order, then open its product info popup and edit it - Rename it and change its price - Confirm the edit dialog - Click on the (renamed) product again to add it to the order Problem: On runbot the tour test_product_create_update_from_frontend (point_of_sale/tests/test_frontend.py, MobileTestUi) intermittently times out waiting for the orderline to sh
Original PR description
Steps to reproduce the bug: - Install point_of_sale - Open the POS frontend and create a new product from the register - Add it to the order, then open its product info popup and edit it - Rename it…
Steps to reproduce the bug:
- Install point_of_sale
- Open the POS frontend and create a new product from the register
- Add it to the order, then open its product info popup and edit it
- Rename it and change its price
- Confirm the edit dialog
- Click on the (renamed) product again to add it to the order
Problem:
On runbot the tour test_product_create_update_from_frontend (point_of_sale/tests/test_frontend.py, MobileTestUi) intermittently times out waiting for the orderline to show the edited product name/quantity/ price combination.
editProduct()'s onSave callback in pos_store.js closed the edit dialog via act_window_close right after firing this.data.read("product.template", ...) and this.data.searchRead("product.product", ...), without waiting for either call to resolve. When the dialog closes before those RPCs land, the in-memory product record used by canBeMergedWith() (pos_order_line.js) to decide how to merge/create the next orderline can still hold the stale price, so re-clicking the product right after editing produces an orderline that never matches the expected quantity/price.
Solution:
Make onSave async and await both this.data.read() and this.data.searchRead() before closing the dialog, so the reactive store is guaranteed to hold the updated product data before the user (or the tour) can interact with the product again.
runbot-223630
Forward-Port-Of: odoo/odoo#279496
Forward-Port-Of: odoo/odoo#277698Steps to Reproduce the Error (Odoo SaaS 19.2): 1. Install l10n_gcc_invoice localization & Accounting 2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings > Configuration > Customer Invoices > Default Terms and Conditions 3. Create invoice with ar_001 partner 4. Confirm the invoice 5. Try to create credit note → Error: KeyError: 'en_US' Root Cause: The _load_narration_translation() workaround reads raw invoice_terms from DB and injects the entire JSONB di
Original PR description
Steps to Reproduce the Error (Odoo SaaS 19.2): 1. Install l10n_gcc_invoice localization & Accounting 2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings >…
Steps to Reproduce the Error (Odoo SaaS 19.2):
1. Install l10n_gcc_invoice localization & Accounting
2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings > Configuration > Customer Invoices > Default Terms and Conditions
3. Create invoice with ar_001 partner
4. Confirm the invoice
5. Try to create credit note → Error: KeyError: 'en_US'
Root Cause:
The _load_narration_translation() workaround reads raw invoice_terms from DB and injects the entire JSONB dict directly into cache, bypassing ORM field conversion. When Odoo 19.2's improved ORM conversion runs, it creates nested JSON in narration instead of a flat structure.
Timeline:
- bedf1cb66fbb: Workaround added to prevent T&C duplication in preview
- 75f050b9650d: Root cause fixed in report template (conditional display) → Made _load_narration_translation() redundant
- 4e4156536bc9: Odoo 19.2 improved ORM conversion → Now conflicts with the redundant workaround, causing nested JSON
How It Breaks:
1. Invoice creation: _load_narration_translation() injects raw dict into cache
2. ORM writes: nested JSON stored: {ar_001: {en_US: ., ar_001: Arabic}}
3. Credit note creation: copy_translations() expects flat structure → Crashes: KeyError: 'en_US'
Why It's Safe to Remove:
Report template already prevents T&C duplication (commit 75f050b9650d). Removing the workaround restores proper credit note creation without breaking T&C display.
Changes:
- Remove moves._load_narration_translation() in create()
- Remove out self.filtered('id')._load_narration_translation() in _compute_narration()
opw : 6284943
Forward-Port-Of: odoo/odoo#271037Before this commit, when a product had a multi choice attribute with only one option, it was not possible to configure the product in the POS or in the self. This is a problem since multi choice are different from other attribute display type because their options are opttional. The user should thus be able to select if he wants the option or not so we should display the configurator even if there is only one option. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.
Original PR description
Before this commit, when a product had a multi choice attribute with only one option, it was not possible to configure the product in the POS or in the self. This is a problem since multi choice are different from other attribute display type because their options are opttional. The user should thus be able to select if he wants the option or not so we should display the configurator even if there is only one option. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#271287
When an internal recipient receives an Out of Office (OOO) notification, the resulting `mail.message` record has `partner_ids` populated with the recipient partner ID, while `outgoing_email_to` is set to `False`. When a second internal user emails the OOO user within the 4-day window, `_notify_thread_with_out_of_office` excutes a search domain with an OR condition: `'|', ('partner_ids', 'in', recipient.ids), ('outgoing_email_to', '=', email_to)` Because `email_to` is `False` for internal p
Original PR description
When an internal recipient receives an Out of Office (OOO) notification, the resulting `mail.message` record has `partner_ids` populated with the recipient partner ID, while `outgoing_email_to` is…
When an internal recipient receives an Out of Office (OOO) notification, the resulting `mail.message` record has `partner_ids` populated with the recipient partner ID, while `outgoing_email_to` is set to `False`.
When a second internal user emails the OOO user within the 4-day window, `_notify_thread_with_out_of_office` excutes a search domain with an OR condition: `'|', ('partner_ids', 'in', recipient.ids), ('outgoing_email_to', '=', email_to)`
Because `email_to` is `False` for internal partners, `('outgoing_email_to', '=', False)` evaluated to `True` against the first recipient's message record. Consequently, the search falsely determined that the second recipient was already notified, suppressing OOO replies for all subsequent contacts across the 4-day window.
## Proposed solution:
We resolve this by dynamically constructing recipient sub-domains conditionally depending if `recipient` or `email_to` are set.
We also extend `test_routing_with_out_of_office` with a corresponding test case.
## How to reproduce:
1. Set up a DB with at least 3 users (User A, User B, User C).
2. Configure User A to be out of office (in user preferences)
3. Go to any chatter/mail.thread while logged as User B and tag User A in a log note. -> triggers OOO message
4. Log as User C, tag User A in a log note. -> BUG: no OOO message because the "4 day" check falsely believes that User C already received a OOO from User A
OPW-6110300
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#277880**PROBLEM** When creating a Credit Note from a Sale Order, the credit note lines uses the default account instead of using the return account set on the company. **STEP TO REPRODUCE** 1. Create a SO with a product. 2. Create an invoice and confirm it. 3. Return to the SO, and reduce the product qty (product invoice policy should be ordered qty for these steps). 4. Click again on create Invoice to create a Credit Note for the SO. 5. Notice the account on the product line is not the retur
Original PR description
**PROBLEM** When creating a Credit Note from a Sale Order, the credit note lines uses the default account instead of using the return account set on the company. **STEP TO REPRODUCE** 1. Create a SO with a product. 2. Create an invoice and confirm it. 3. Return to the SO, and reduce the product qty (product invoice policy should be ordered qty for these steps). 4. Click again on create Invoice to create a Credit Note for the SO. 5. Notice the account on the product line is not the return account. **CAUSE** In `_create_invoices()` on the SO model, we first create the moves as invoice, and then switch them to credit note if the total is negative. This means the lines are created with the invoice default account. opw-6266882 Forward-Port-Of: odoo/odoo#274354
**Issue** The package of the selected quant is not proposed as a destination package when adding stock move lines manually before the move line is saved. **Steps to reproduce** - Activate 'Packages' in the settings - Create a tracked product with package - Put 10 units in stock in package `P`. - Create and confirm a sale for 5 units - Open the delivery, make sure the quantity is set to 0 - Click 'Details' - "Add a line" and select the package P -> if you try to select a destination p
Original PR description
**Issue** The package of the selected quant is not proposed as a destination package when adding stock move lines manually before the move line is saved. **Steps to reproduce** - Activate 'Packages'…
**Issue** The package of the selected quant is not proposed as a destination package when adding stock move lines manually before the move line is saved. **Steps to reproduce** - Activate 'Packages' in the settings - Create a tracked product with package - Put 10 units in stock in package `P`. - Create and confirm a sale for 5 units - Open the delivery, make sure the quantity is set to 0 - Click 'Details' - "Add a line" and select the package P -> if you try to select a destination package, the package P is not proposed as it should - save it and reopen 'Details' -> if you try to select a destination package, the package P is now proposed **Cause** The domain of `result_package_id` (destination package) correctly includes `package_id`: https://github.com/odoo/odoo/blob/3a5f7431effd4b2b2eb8ce3eed81aaba42fcd8ea/addons/stock/models/stock_move_line.py#L52-L56 However, before saving, `package_id` is not yet populated into the new `stock.move.line` record. It will only be copied from `quant_id` by `_copy_quant_info()`: https://github.com/odoo/odoo/blob/3a5f7431effd4b2b2eb8ce3eed81aaba42fcd8ea/addons/stock/models/stock_move_line.py#L1016-L1025 which will only be called in the create method, while saving: https://github.com/odoo/odoo/blob/3a5f7431effd4b2b2eb8ce3eed81aaba42fcd8ea/addons/stock/models/stock_move_line.py#L350 opw-6370159 Forward-Port-Of: odoo/odoo#277797
Before this commit, the unread banner could stop showing in a channel until it was left and opened again: - open a channel with unread messages - click "Mark as Read" - read the same channel from another device - receive a new message: the server counter increases, still no banner This happens because an implicit mark as read freezes the local unread state, so the banner stays in place while the user reads. The problem is that it stays frozen even after the banner is gone, and never fol
Original PR description
Before this commit, the unread banner could stop showing in a channel until it was left and opened again: - open a channel with unread messages - click "Mark as Read" - read the same channel from another device - receive a new message: the server counter increases, still no banner This happens because an implicit mark as read freezes the local unread state, so the banner stays in place while the user reads. The problem is that it stays frozen even after the banner is gone, and never follows the server counter again. This commit freezes that state only while something is still unread locally. This also fixes the flaky test "no unread message banner after message is deleted". https://runbot.odoo.com/odoo/error/242776 Forward-Port-Of: odoo/odoo#279601 Forward-Port-Of: odoo/odoo#279195
This pull request addresses several key updates to the Chilean tax reporting functionality within Odoo. Specifically, it incorporates new tax categories, corrects fiscal position calculations, and improves data consistency for accurate reporting. These changes ensure compliance with updated Chilean tax regulations.
Original PR description
added tags for accounts and new demo data for l10n_cl_reports f29 refactor refactor file to company_demo.xml Add widthholding tax 2nd category for 2027 and 2028 since it is suitable for this report compatibility [FIX] l10n_cl: add more taxes and fix translation [FIX] l10n_cl: adapt fiscal position to new scheme. [FIX] l10n_cl: remove unused tags [FIX] l10n_cl: add fiscal position to taxes and replacement tax. Change refs in demo and fix demo values to make more consistent with real cases [FIX] l10n_cl: change monthy taxes payable 210760 from payable to current [FIX] l10n_cl: add new ILA accounts to COA and fix ILA tax repartition lines Compatibility with 'remove tax_tag_invert' [FIX] l10n_cl: fix 'compras de combustibles' task-4329648 Forward-Port-Of: odoo/odoo#247545
This update fixes an issue where styles weren't consistently removed from notes, specifically when creating links. The change ensures that styles are correctly cleared from all selected text, regardless of whether it's a standard note or a linked element. This improves the overall note editing experience.
Original PR description
When a format is applied on an unsplittable node, removing it from a wider selection does not dare to touch that format to ensure it won't be split. Because of this, it becomes impossible to remove the format on such nodes. This commit slightly adapts the logic by so that instead of stopping when encountering an unsplittable node, it keeps looking higher in the hierarchy where the format is actually defined. Steps to reproduce: - Go to a "To do" note - Select a word - Apply a style (underscore, strikethrough...) - Type "odoo.com" - Press space to turn it into a link - Select the whole line - Try to remove the style => The style was not removed from the link. task-6322596 Forward-Port-Of: odoo/odoo#279511 Forward-Port-Of: odoo/odoo#273922
This update ensures that customer signatures are consistently included in order confirmation PDFs, regardless of whether online payment is enabled. Previously, signatures were missing when using online payment, and this fix corrects a technical issue related to context settings within the order confirmation process. This improves customer satisfaction and provides a more complete record of the sale.
Original PR description
**Steps to reproduce:** 1. Create a new SO and enable "Online Signature" and "Online Payment" in the "Other Info" tab 2. Click on Preview and click on "Sign & Pay" from the portal (demo payment…
**Steps to reproduce:** 1. Create a new SO and enable "Online Signature" and "Online Payment" in the "Other Info" tab 2. Click on Preview and click on "Sign & Pay" from the portal (demo payment should be enabled from the settings to proceed) 3. Once the transaction is processed and the order confirmed, check the confirmation email/PDF sent to the customer in the chatter **Issue:** - The order confirmation sent to the customer after paying online does not include the signature they provided when accepting the quotation - Even if "Online Payment" is not enabled and Signing will directly confirm the order, the signature is still missing. **Why this happens:** - The signature block in `sale.report_saleorder_document` is gated by the `sale_include_signature` context key rather than solely by doc.signature. This was introduced by commit ef8246a4daf6146da2ed3cb78c37c7bf0937a4df to retain signature integrity. - `portal_quote_accept` only sets this context right after the customer signs on the pdf rendered for us (company), and was not passed through `_validate_order()` when there was no online payment - When online payment is required, `_has_to_be_paid()` defers the order confirmation which happens later, and the context is never set elsewhere **Fix:** - Pass the context when online payment is not required - If online payment is required, the sale quotation can be modified after being signed. However, since the customer previews the quotation when Paying, we can say the signature integrity is retained opw-6389733 Forward-Port-Of: odoo/odoo#278854
10 changes
Enhancements to existing features
Forward-Port-Of: odoo/odoo#278655
Original PR description
Forward-Port-Of: odoo/odoo#278655
Resolved issues and error corrections
Purpose of this PR: - On double click, opening the toolbar is delayed by 300ms to prevent flickering before a potential triple click. - However, mouseup was re-enabling selection tracking (onSelectionChangeActive = true) before the 300ms delay finished. Because browser selectionchange events are dispatched asynchronously after mouseup, they triggered updateToolbar() immediately, bypassing the 300ms delay. - This fix re-enables selection tracking only after the 300ms debounced update actuall
Original PR description
Purpose of this PR: - On double click, opening the toolbar is delayed by 300ms to prevent flickering before a potential triple click. - However, mouseup was re-enabling selection tracking (onSelectionChangeActive = true) before the 300ms delay finished. Because browser selectionchange events are dispatched asynchronously after mouseup, they triggered updateToolbar() immediately, bypassing the 300ms delay. - This fix re-enables selection tracking only after the 300ms debounced update actually finishes. runbot-941543 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278025
Since I cannot push to https://github.com/odoo-dev/odoo, this PR is a parallel one to [#279530](https://github.com/odoo/odoo/pull/279530). It shows how to fix the #279530 which has a merge conflict. Forward-Port-Of: [#266261](https://github.com/odoo/odoo/pull/266261) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
Since I cannot push to https://github.com/odoo-dev/odoo, this PR is a parallel one to [#279530](https://github.com/odoo/odoo/pull/279530). It shows how to fix the #279530 which has a merge conflict. Forward-Port-Of: [#266261](https://github.com/odoo/odoo/pull/266261) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
**PROBLEM** When using fixed tax not affecting the base on line with discount, the xml generated is invalid and refused by peppol. **STEP TO REPRODUCE** 1. Install l10n_be. 2. Create an invoice with the following line: - qty: 2, price_unit: 100, discount: 10%, taxes: 21% + fixed tax 1€ - qty: -2, price_unit: 0, taxes: fixed tax 1€ 3. Generate an xml, and try validating it on peppol. 4. The validation fails with the error: [BR-27]-The Item net price (BT-146) shall NOT be negative.
Original PR description
**PROBLEM** When using fixed tax not affecting the base on line with discount, the xml generated is invalid and refused by peppol. **STEP TO REPRODUCE** 1. Install l10n_be. 2. Create an invoice with…
**PROBLEM** When using fixed tax not affecting the base on line with discount, the xml generated is invalid and refused by peppol. **STEP TO REPRODUCE** 1. Install l10n_be. 2. Create an invoice with the following line: - qty: 2, price_unit: 100, discount: 10%, taxes: 21% + fixed tax 1€ - qty: -2, price_unit: 0, taxes: fixed tax 1€ 3. Generate an xml, and try validating it on peppol. 4. The validation fails with the error: [BR-27]-The Item net price (BT-146) shall NOT be negative. **CAUSE** Fixed tax not affecting the base of other tax are dispatched into new base lines and then merged into one line per fixed tax. The new base lines they are dispatched to are created as a copy of the line they originated from. It means we copy the discount from the original lines. The fixed tax amount is the unit price of each new base lines. When reducing the base lines into one line, we take the unit prices of the line, and apply the discount to the unit price. But, since the unit price is the fixed tax amount, and fixed tax are not affected by discounts, we shouldn't apply discount. **PROBLEM 2** fixed division by 0 traceback when the aggregation of invoice lines is 0 **STEP TO REPRODUCE** 1. Install l10n_be. 2. Create the following invoice: - qty: 1, unit_price: 100, tax:0% + fixed tax 1€, set an analytic distribution account - qty: -1, unit_price: 50, tax:0% + fixed tax 1€, set the same analytic distribution account 3. Send the invoice to peppol. 4. A division by 0 should occur. opw-6388219
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#277531
The JsonFormatter has two bugs - the ignore list is not working as expected - in 18.0-18.4 the 'test' key is broken This commit add tests to ensure those behavior works as expected While on it, also adds a `additional_record_keys` parameter to allow to specifically add keys to the default list, without having to override the whole list, and add additional default keys (exc_info and test) The previous `ignored_record_keys` default value was possible to remove by calling `JSONFormatte
Original PR description
The JsonFormatter has two bugs - the ignore list is not working as expected - in 18.0-18.4 the 'test' key is broken This commit add tests to ensure those behavior works as expected While on it, also…
The JsonFormatter has two bugs - the ignore list is not working as expected - in 18.0-18.4 the 'test' key is broken This commit add tests to ensure those behavior works as expected While on it, also adds a `additional_record_keys` parameter to allow to specifically add keys to the default list, without having to override the whole list, and add additional default keys (exc_info and test) The previous `ignored_record_keys` default value was possible to remove by calling `JSONFormatter(ignore_record_keys=[])` The purpose was to be able to easily include all keys and ignore the default ingnore list, but this makes the additional blacklisting of a few keys more tedious, and the general usage and implementation more complex `JSONFormatter(ignore_record_keys=[*JSONFormatter.DEFAULT_IGNORED_RECORD_KEYS, 'other key'])` To simplify the logic, **this is not the case anymore**, so to include all keys something like this would be needed `JSONFormatter(additional_record_keys=JSONFormatter.DEFAULT_IGNORED_RECORD_KEYS)` Or an hardcoded list. Forward-Port-Of: odoo/odoo#279344 Forward-Port-Of: odoo/odoo#279049
### Steps to Reproduce: 1. Make sure that the Sale and Inventory modules are installed 2. Enable Multi-Step Routes and Packages in Inventory Configurations 3. Warehouse configuration > Outgoing shipments > Select Pick then Deliver (2 steps) 4. Routes > Deliver in 2 steps (pick + ship) > Pull From > Destination Location > Select WH/Output 5. Routes > Deliver in 2 steps (pick + ship) > Push To > Action > Change to Pull From 6. Operation Types > Delivery Orders > Packages > Enable Move Entire
Original PR description
### Steps to Reproduce: 1. Make sure that the Sale and Inventory modules are installed 2. Enable Multi-Step Routes and Packages in Inventory Configurations 3. Warehouse configuration > Outgoing…
### Steps to Reproduce: 1. Make sure that the Sale and Inventory modules are installed 2. Enable Multi-Step Routes and Packages in Inventory Configurations 3. Warehouse configuration > Outgoing shipments > Select Pick then Deliver (2 steps) 4. Routes > Deliver in 2 steps (pick + ship) > Pull From > Destination Location > Select WH/Output 5. Routes > Deliver in 2 steps (pick + ship) > Push To > Action > Change to Pull From 6. Operation Types > Delivery Orders > Packages > Enable Move Entire Packages 7. Go to any product, ex. Drawer > On Hand > Set original on hand qty to 16 and new lot to 50 8. Create a new SO and make 2 lines, with the same product, and change the second line's price to something else, ex. 80.0 9. Deliveries > WH/PICK/00001 > Set quantity to 4 > Put in Pack > Validate and Create Backorder 10. WH/PICK/00002 > Put in Pack > Validate 11. WH/OUT/00012 > Mark PACK0000001 Done > Save. Observe how the first line quantity is changed from 3 to 4 12. Mark PACK0000002 Done > Save > Validate > Observe how it's asking for a backorder even though we already packed all 5 items. ### Description of the issue/feature this PR addresses: Instead of using the `product_qty` from the stock move, use the quantity of the move line to correctly allocate the quantities in StockPackageLevel ### Current behavior before PR: In the Shop Floor when loading packages, marking the package level as done causes issues on the quantity processed on the corresponding move lines. On stock transfers, we currently allocate the Quantity Done to the wrong product line. The total quantity is correct, but the distribution across lines does not match the Demand values. This causes the transfer to remain stuck in Reserved, even though the shipment was already processed operationally. ### Desired behavior after PR is merged: The correct quantity from the move line is used and this resolves the issue with quantity distribution not matching move line quantities when using packages. opw-6040640 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#242487
Problem: When creating inline code from formatted text, the formatting is not preserved for the text that follows the inline code. Solution: Preserve the active text formatting (e.g., bold, italic, underline) when inserting inline code, ensuring subsequent text on the same line retains the previously applied styles. Steps to reproduce: - Go to To-Do → Create New. - Type some text in bold. - Insert an inline code block. - Continue typing after the inline code. - Observe that the text
Original PR description
Problem: When creating inline code from formatted text, the formatting is not preserved for the text that follows the inline code. Solution: Preserve the active text formatting (e.g., bold, italic, underline) when inserting inline code, ensuring subsequent text on the same line retains the previously applied styles. Steps to reproduce: - Go to To-Do → Create New. - Type some text in bold. - Insert an inline code block. - Continue typing after the inline code. - Observe that the text after the inline code is no longer bold. opw-6395163 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276943
The amount in words split the total with int(decimal * 100), which truncates. 3989.33 is held in binary as 3989.3299..., so the kuruş/cents came out one short (32 instead of 33). The written amount then disagreed with the numeric total on the same invoice and Nilvera rejects it. Round to the currency precision and round the subunit instead. Task-6383690 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: ---
Original PR description
The amount in words split the total with int(decimal * 100), which truncates. 3989.33 is held in binary as 3989.3299..., so the kuruş/cents came out one short (32 instead of 33). The written amount then disagreed with the numeric total on the same invoice and Nilvera rejects it. Round to the currency precision and round the subunit instead. Task-6383690 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#277748 Forward-Port-Of: odoo/odoo#277180
Steps to Reproduce the Error (Odoo SaaS 19.2): 1. Install l10n_gcc_invoice localization & Accounting 2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings > Configuration > Customer Invoices > Default Terms and Conditions 3. Create invoice with ar_001 partner 4. Confirm the invoice 5. Try to create credit note → Error: KeyError: 'en_US' Root Cause: The _load_narration_translation() workaround reads raw invoice_terms from DB and injects the entire JSONB di
Original PR description
Steps to Reproduce the Error (Odoo SaaS 19.2): 1. Install l10n_gcc_invoice localization & Accounting 2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings >…
Steps to Reproduce the Error (Odoo SaaS 19.2):
1. Install l10n_gcc_invoice localization & Accounting
2. Activate Arabic language (ar_001) and add Default Terms and Conditions in Settings > Configuration > Customer Invoices > Default Terms and Conditions
3. Create invoice with ar_001 partner
4. Confirm the invoice
5. Try to create credit note → Error: KeyError: 'en_US'
Root Cause:
The _load_narration_translation() workaround reads raw invoice_terms from DB and injects the entire JSONB dict directly into cache, bypassing ORM field conversion. When Odoo 19.2's improved ORM conversion runs, it creates nested JSON in narration instead of a flat structure.
Timeline:
- bedf1cb66fbb: Workaround added to prevent T&C duplication in preview
- 75f050b9650d: Root cause fixed in report template (conditional display) → Made _load_narration_translation() redundant
- 4e4156536bc9: Odoo 19.2 improved ORM conversion → Now conflicts with the redundant workaround, causing nested JSON
How It Breaks:
1. Invoice creation: _load_narration_translation() injects raw dict into cache
2. ORM writes: nested JSON stored: {ar_001: {en_US: ., ar_001: Arabic}}
3. Credit note creation: copy_translations() expects flat structure → Crashes: KeyError: 'en_US'
Why It's Safe to Remove:
Report template already prevents T&C duplication (commit 75f050b9650d). Removing the workaround restores proper credit note creation without breaking T&C display.
Changes:
- Remove moves._load_narration_translation() in create()
- Remove out self.filtered('id')._load_narration_translation() in _compute_narration()
opw : 6284943
Forward-Port-Of: odoo/odoo#2710373 changes
Resolved issues and error corrections
Description of the issue/feature this PR addresses: Downloading an attachment from the file viewer fails with a `405 Method Not Allowed` error when the attachment belongs to a Discuss channel. I've already submitted a ticket to Odoo: #6430586 Steps to reproduce (on a 18.0 runbot): 1. open Discuss and send an image in a channel 2. click the image to open the file viewer 3. click the download button (either the one in the header or the one in the bottom toolbar) The server rejec
Original PR description
Description of the issue/feature this PR addresses: Downloading an attachment from the file viewer fails with a `405 Method Not Allowed` error when the attachment belongs to a Discuss channel. I've…
Description of the issue/feature this PR addresses:
Downloading an attachment from the file viewer fails with a `405 Method Not Allowed` error when the attachment belongs to a Discuss channel.
I've already submitted a ticket to Odoo: #6430586
Steps to reproduce (on a 18.0 runbot):
1. open Discuss and send an image in a channel
2. click the image to open the file viewer
3. click the download button (either the one in the header or the one in the bottom
toolbar)
The server rejects the request:
```
POST /discuss/channel/1/image/519861?filename=image.png&unique=32647b0f&download=true 405
```
and the user gets a `RPC_ERROR: Arbitrary Uncaught Python Exception` dialog reporting `405 Method Not Allowed`.
Cause: `download()` always issues a POST request, while the routes serving the attachments of a discuss channel only allow GET:
* `/discuss/channel/<int:channel_id>/attachment/<int:attachment_id>`
* `/discuss/channel/<int:channel_id>/image/<int:attachment_id>`
so the request never reaches the controller. Downloading the very same attachment from the attachment card in the conversation still works, because that one is a plain anchor navigation (GET).
This is a regression from fb152985f4b8 ("[FIX] web: download FileViewer files via blob helper"), which routed the file viewer download through `download()` in order to honor the filename sent by the server in the `Content-Disposition` header.
Only 18.0 is affected: saas-18.1 and saas-18.2 do not have the commit that introduced the regression, and from saas-18.3 on, the `urlRoute` override was dropped and channel attachments are served through the standard `/web/content` and /web/image` routes, which are not restricted to GET.
The download is still sent with POST on those branches though, hence forward-porting this up to master.
Current behavior before PR:
Downloading a Discuss channel attachment from the file viewer raises a 405 error and the file is not downloaded. Images and other file types are equally affected.
Desired behavior after PR is merged:
The file is downloaded, keeping the filename advertised by the server. The download is performed with a GET request through `downloadFile()`, which still goes through the blob helper, so the fix of fb152985f4b8 is preserved. This is already the way a file is downloaded from its url in `readonly_file.js`.
Added a test that downloads an image attachment of a channel from the file viewer and asserts the request is a GET on the channel attachment route. It fails before this fix with `POST /discuss/channel/1/image/1`.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr### Steps to reproduce: - Open Website app - Go to Theme > Fonts, select "Borel" as a Google Font (self-hosted, i.e. "Serve fonts from Google" toggle left off) > The text renders shifted upward relative to its container, appearing cut off at the top or off-center inside buttons/badges. ### Cause of Issue: When a Google Font is self-hosted, `Assets.make_scss_customization()` fetches the font's CSS from Google and rewrites only the `src: url(...)` declaration of each `@font-face` block t
Original PR description
### Steps to reproduce: - Open Website app - Go to Theme > Fonts, select "Borel" as a Google Font (self-hosted, i.e. "Serve fonts from Google" toggle left off) > The text renders shifted upward…
### Steps to reproduce: - Open Website app - Go to Theme > Fonts, select "Borel" as a Google Font (self-hosted, i.e. "Serve fonts from Google" toggle left off) > The text renders shifted upward relative to its container, appearing cut off at the top or off-center inside buttons/badges. ### Cause of Issue: When a Google Font is self-hosted, `Assets.make_scss_customization()` fetches the font's CSS from Google and rewrites only the `src: url(...)` declaration of each `@font-face` block to point at Odoo's own `ir.attachment`, leaving the rest of the block untouched: https://github.com/odoo/odoo/blob/5cbcf18762f08439c2dfeed17317a391fe89f074/addons/website/models/assets.py#L82-L103 Script fonts like Borel declare an ascent/descent ratio that is much larger than their visible glyph ink, so any layout that vertically centers text centers around a line box that sits noticeably higher than what's actually drawn on screen. ### Fix: Added a small dict (`GOOGLE_FONT_METRIC_OVERRIDES`) that maps affected font names to their tuned override values, so only fonts confirmed to have the issue are touched and every other Google Font keeps rendering exactly as before. This would also be useful in future use, in case it's needed to manipulate any fonts' aspects. opw-6373800
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
1 change
Resolved issues and error corrections
**Steps to reproduce:** 1. Install Accounting and l10n_be and switch to the Belgian company 2. In the settings, set the discount account (`708000`) on Customer Invoices under "Default Accounts" and enable analytic accounting 3. Go to [Accounting -> Configuration -> Analytic Accounts] and create 4 new accounts with "Project" plan (i.e 1,2,3,4) 4. Create a new invoice with two lines, each having 2 of the analytic accounts with 50% each. 5. Set the price to 1000 and a 10% discount for each lin
Original PR description
**Steps to reproduce:** 1. Install Accounting and l10n_be and switch to the Belgian company 2. In the settings, set the discount account (`708000`) on Customer Invoices under "Default Accounts" and…
**Steps to reproduce:** 1. Install Accounting and l10n_be and switch to the Belgian company 2. In the settings, set the discount account (`708000`) on Customer Invoices under "Default Accounts" and enable analytic accounting 3. Go to [Accounting -> Configuration -> Analytic Accounts] and create 4 new accounts with "Project" plan (i.e 1,2,3,4) 4. Create a new invoice with two lines, each having 2 of the analytic accounts with 50% each. 5. Set the price to 1000 and a 10% discount for each line then save. 6. Edit the second line and set the discount to 20%. 7. Open the Journal Items tab **Issue:** - When an invoice contains multiple lines with analytic distributions, changing the discount percentage on any line other than the first fails to correctly update the analytic distribution percentages on the corresponding discount journal items. - The analytic account distribution splits the percentage evenly across both accounts event if they are not split 50/50 **Why this happens:** - This occurred because `_compute_discount_allocation_needed` iterated over `self` to populate target changes. When only one line was modified, `self` contains that line only which is correctly updated with the new analytic distribution. Later in the execution in `_sync_dynamic_line`, particularly in https://github.com/odoo/odoo/blob/5a14360705a55f4d91edf39c936d7a5d8573044b/addons/account/models/account_move.py#L2263-L2274 The first line in `computed_needed` is what gets set in res, and subsequent lines only modify the field if it's monetary. So if the second invoice line is the one updated, it will never override the `analytic_distribution` with the updated values, leaving stale values in that field. - The code iterated directly over `line.analytic_distribution` dictionary keys (the account IDs) rather than its `.items()`. This caused it to ignore the individual percentage value splits (e.g. 60/40), accumulating the un-weighted full discount amount to each account ID. https://github.com/odoo/odoo/blob/5a14360705a55f4d91edf39c936d7a5d8573044b/addons/account/models/account_move_line.py#L1044-L1052 **Fix:** - Change the processing loop inside `_compute_discount_allocation_needed` from `self` to `self.move_id.line_ids` to calculate the correct `analytic_distribution` across all records. - Applying the factored weight ratio (`amount * (percentage / 100.0)`) to `distribution_totals` opw-6362084