Daily updates from Odoo
Thursday, July 23, 2026
273 changes
18 changes
Enhancements to existing features
Motivation ---------- Each database served keeps a full registry in a process-wide LRU. The LRU is bounded by a count, so on a server hosting thousands of databases the number of retained registries follows traffic rather than memory pressure. Their combined footprint can push a worker past its virtual-memory soft limit, at which point it is killed and restarted. On a server with ~2500 databases, the soft limit is reached at ~180 resident databases while the LRU could still hold ~210, so HT
Original PR description
Motivation ---------- Each database served keeps a full registry in a process-wide LRU. The LRU is bounded by a count, so on a server hosting thousands of databases the number of retained registries…
Motivation ---------- Each database served keeps a full registry in a process-wide LRU. The LRU is bounded by a count, so on a server hosting thousands of databases the number of retained registries follows traffic rather than memory pressure. Their combined footprint can push a worker past its virtual-memory soft limit, at which point it is killed and restarted. On a server with ~2500 databases, the soft limit is reached at ~180 resident databases while the LRU could still hold ~210, so HTTP workers were being recycled under normal load. Tracking usage -------------- Every request for a registry goes through the single lookup in the registry constructor, which now stamps it with a monotonic timestamp; the stamp is also set when a registry is first built. Collecting idle registries -------------------------- A collection pass drops every registry whose last use is older than the configured idle timeout. It runs at the end of registry loading, so it fires periodically as databases come and go. Registries that are still loading are skipped, so a concurrent build is never collected. Dropping a registry only detaches it from the LRU: a request still holding a reference keeps working, and the next lookup rebuilds it. The timeout is read from ODOO_REGISTRY_MAX_IDLE_TIMEOUT, in seconds; a value of zero, the default, disables the mechanism so behaviour is unchanged unless it is opted into. Results ------- With a five-minute timeout on the same ~2500-database server, the HTTP workers settle at around 40 resident registries instead of saturating memory on the long run. The gevent worker, which sees every web client reconnect at startup and briefly fills the LRU with ~150 databases, releases most of them on the first pass, reclaiming the memory. On a real-life SaaS server with 64GB of RAM, that frees up to ~10GB which were previously taken by unused registries in the LRU. It comes at the expense of extra registry recomputes, but on the other hand workers do not reach their virtual memory limit anymore. 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
Unlink operations are logged by default, which is useful for auditing most records. However, unlink operations on last interest records and cron triggers happen frequently and provide little auditing value. This PR mutes the unlink logger for these records to avoid filling the logs with repetitive entries, especially when a large number of messages are posted in parallel. task-6400122 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
Unlink operations are logged by default, which is useful for auditing most records. However, unlink operations on last interest records and cron triggers happen frequently and provide little auditing value. This PR mutes the unlink logger for these records to avoid filling the logs with repetitive entries, especially when a large number of messages are posted in parallel. task-6400122 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Resolved issues and error corrections
## Problem When generating accrual entries for multiple sale orders, the stock variation lines would all show the same order name, even if the line belonged to a different sale order. This is caused by the `order` variable being reused from a previous loop. ## Solution We will pull the order name directly from the order line in the current iteration. ## Steps to reproduce (Runbot v19) 1. Create a product with AVCO perpetual valuation 2. Make sure all accounts are configured properly (I
Original PR description
## Problem When generating accrual entries for multiple sale orders, the stock variation lines would all show the same order name, even if the line belonged to a different sale order. This is caused…
## Problem When generating accrual entries for multiple sale orders, the stock variation lines would all show the same order name, even if the line belonged to a different sale order. This is caused by the `order` variable being reused from a previous loop. ## Solution We will pull the order name directly from the order line in the current iteration. ## Steps to reproduce (Runbot v19) 1. Create a product with AVCO perpetual valuation 2. Make sure all accounts are configured properly (Income, Expense, Stock, and stock variation accounts) 3. Add units to the stock (it can be with an adjustment, as long as the product has a cost already set) 4. Create 2 separate sales orders for this product 5. Deliver both of the sales orders, do not invoice them 6. Now go to the Accounting App Review>Invoices to be issued 7. Select the 2 invoices that were created. The Revenue accrual lines are correct, with each SO being referenced, but on the Stock variation lines, only the last SO selected will appear. opw-6361032 Forward-Port-Of: odoo/odoo#277058
Before this commit, the maximum weight and volume allowed on a delivery method were checked against transfers using the quantity in the unit of the move, while the weight and volume of a product are expressed per reference unit. The same checks on sale orders already use the quantity in the reference unit. Steps to reproduce: - create a delivery method with a maximum weight of 10 kg - create a product in Units weighing 1 kg with Dozens in its allowed units - create a delivery transfer of 2
Original PR description
Before this commit, the maximum weight and volume allowed on a delivery method were checked against transfers using the quantity in the unit of the move, while the weight and volume of a product are…
Before this commit, the maximum weight and volume allowed on a delivery method were checked against transfers using the quantity in the unit of the move, while the weight and volume of a product are expressed per reference unit. The same checks on sale orders already use the quantity in the reference unit. Steps to reproduce: - create a delivery method with a maximum weight of 10 kg - create a product in Units weighing 1 kg with Dozens in its allowed units - create a delivery transfer of 2 Dozen of the product and select the carrier on the transfer The 24 kg shipment is weighed as 2 kg, so the carrier is proposed on the transfer although it exceeds its maximum weight, and it is correctly refused on a sale order for the same quantity. With a unit smaller than the reference one, valid carriers are hidden instead. Solution: Use the quantity in the reference unit of the product, as done for sale orders and everywhere else the shipment weight is computed. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277708 Forward-Port-Of: odoo/odoo#277425
Before this fix, if a custom group was added in an Odoo PIVOT in a spreadsheet, without sorting, the custom group name was added to the RPC kwards.order, causing a server error. After this fix, the custom group name is removed from the RPC kwards.order. Task: 6401442 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277478
Original PR description
Before this fix, if a custom group was added in an Odoo PIVOT in a spreadsheet, without sorting, the custom group name was added to the RPC kwards.order, causing a server error. After this fix, the custom group name is removed from the RPC kwards.order. Task: 6401442 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277478
in odoo/odoo#260278, the repair linked lines (stock moves and account move lines) were refactored in order to handle newer changes in a cleaner way but the `_clean_repair_linked_lines` method call was missing its braces. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
in odoo/odoo#260278, the repair linked lines (stock moves and account move lines) were refactored in order to handle newer changes in a cleaner way but the `_clean_repair_linked_lines` method call was missing its braces. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Note: In odoo all date/datetime fields are stored and computed by default as UTC Before this commit, dates were called using local timezone getters. This caused the time returned from web to be shifted by the timezone as the dates returned would be treated as UTC. After this commit, dates are now called using UTC timzone getters. Now all web times are retrived as UTC and in sync with the rest of the odoo fields and computations. task-6271421 Forward-Port-Of: odoo/odoo#276683 Forward-Po
Original PR description
Note: In odoo all date/datetime fields are stored and computed by default as UTC Before this commit, dates were called using local timezone getters. This caused the time returned from web to be shifted by the timezone as the dates returned would be treated as UTC. After this commit, dates are now called using UTC timzone getters. Now all web times are retrived as UTC and in sync with the rest of the odoo fields and computations. task-6271421 Forward-Port-Of: odoo/odoo#276683 Forward-Port-Of: odoo/odoo#265250
v19 WIoT Boxes will be listening on localhost when updating to v19.1+, we need to ensure they use `http_interface = 0.0.0.0` after the update. Forward-Port-Of: odoo/odoo#276655 Forward-Port-Of: odoo/odoo#272063
Original PR description
v19 WIoT Boxes will be listening on localhost when updating to v19.1+, we need to ensure they use `http_interface = 0.0.0.0` after the update. Forward-Port-Of: odoo/odoo#276655 Forward-Port-Of: odoo/odoo#272063
The footer slideout state was computed only once during interaction setup. If the main content height changed afterward, e.g. in edit mode: dropping or removing snippets, or resizing the window, the effect could remain enabled/disabled even though the content had become taller/shorter than the viewport. Steps to reproduce: - Go into edit mode - Add two snippets on the page - On the footer, set the "Slideout Effect" option to "Slide Hover" - Remove one snippet - Half of the footer is
Original PR description
The footer slideout state was computed only once during interaction setup. If the main content height changed afterward, e.g. in edit mode: dropping or removing snippets, or resizing the window, the effect could remain enabled/disabled even though the content had become taller/shorter than the viewport. Steps to reproduce: - Go into edit mode - Add two snippets on the page - On the footer, set the "Slideout Effect" option to "Slide Hover" - Remove one snippet - Half of the footer is hidden by the hover effect, which should not happen task-6117257 Forward-Port-Of: odoo/odoo#277614 Forward-Port-Of: odoo/odoo#275291
Steps: - Enable `pos_hr` and configure employees - Open the POS - Log in as an employee - Open the burger menu in the navbar Issue: - The "Create Product" menu is not visible immediately after the employee logs in. - It only appears after refreshing the POS. Cause: - The visibility of the menu is determined when `Navbar` component is mounted. - Since the `Navbar` is mounted only once when the POS UI loads, the value is not updated after employee login. Fix: - Replace the asynch
Original PR description
Steps: - Enable `pos_hr` and configure employees - Open the POS - Log in as an employee - Open the burger menu in the navbar Issue: - The "Create Product" menu is not visible immediately after the employee logs in. - It only appears after refreshing the POS. Cause: - The visibility of the menu is determined when `Navbar` component is mounted. - Since the `Navbar` is mounted only once when the POS UI loads, the value is not updated after employee login. Fix: - Replace the asynchronous permission check with a getter that evaluates product creation rights. - Cache the group access information in `posService` and let the hr override use the getter. Task-6361787 Related PR: https://github.com/odoo/enterprise/pull/123073 Forward-Port-Of: odoo/odoo#277753 Forward-Port-Of: odoo/odoo#274420
Current behavior before PR: - Updating a chart granularity was overriding searchParams from `definition.searchParams` instead of `definition.dataSource.searchParams.` - Since `definition.searchParams` is undefined, all existing search parameters, such as domain, were lost. Desired behavior after PR is merged: - Read searchParams from definition.dataSource.searchParams before updating the granularity. - This preserves the existing search parameters while updating only the group
Original PR description
Current behavior before PR: - Updating a chart granularity was overriding searchParams from `definition.searchParams` instead of `definition.dataSource.searchParams.` - Since `definition.searchParams` is undefined, all existing search parameters, such as domain, were lost. Desired behavior after PR is merged: - Read searchParams from definition.dataSource.searchParams before updating the granularity. - This preserves the existing search parameters while updating only the groupBy value. Task: [6377572](https://www.odoo.com/odoo/project/2328/tasks/6377572) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276244
**Steps to reproduce:** * Install l10n_fr. * Create an invoice using a tax with the E3 tax grid. * Post the invoice so it is included in the tax report. * Open the French tax report. **Observed Behaviour:** The E3 line is blank even though the amount is present in the report data. The amount is recorded as a negative value, while the report formula expects a positive value, causing it to be deducted from the report total. **Cause:** The E3 tax report expression used the for
Original PR description
**Steps to reproduce:** * Install l10n_fr. * Create an invoice using a tax with the E3 tax grid. * Post the invoice so it is included in the tax report. * Open the French tax report. **Observed Behaviour:** The E3 line is blank even though the amount is present in the report data. The amount is recorded as a negative value, while the report formula expects a positive value, causing it to be deducted from the report total. **Cause:** The E3 tax report expression used the formula E3, which does not account for tax grid amounts stored as negative values. **Fix:** Update the E3 report expression formula from E3 to -E3 so that negative E3 amounts are correctly displayed in the tax report. opw - 6321790 Forward-Port-Of: odoo/odoo#274052
Before this commit, the res.users model was not being loaded in the POS when reloading data. If user A was logged in and then on the same device user B logged in, it would not load the new user B data, and it causes user B to not be able to go to the backend. opw-6388954 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276546
Original PR description
Before this commit, the res.users model was not being loaded in the POS when reloading data. If user A was logged in and then on the same device user B logged in, it would not load the new user B data, and it causes user B to not be able to go to the backend. opw-6388954 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276546
Issue: On an invoice PDF, using a layout with the address on the left. If a contact has a delivery address, but the option "Customer address" is not set, address will be displayed on the right instead of the left. Steps to reproduce: - Create a customer - Add a Delivery address to the customer - Ensure "Customer Address" is not set in the settings - Choose a layout with the address on the left (bubble, wave, ...) - Create an invoice to the customer - print the PDF Current behavior:
Original PR description
Issue: On an invoice PDF, using a layout with the address on the left. If a contact has a delivery address, but the option "Customer address" is not set, address will be displayed on the right instead of the left. Steps to reproduce: - Create a customer - Add a Delivery address to the customer - Ensure "Customer Address" is not set in the settings - Choose a layout with the address on the left (bubble, wave, ...) - Create an invoice to the customer - print the PDF Current behavior: - Customer address is on the right Expected behavior: - Customer address is on the left Cause: Address is displayed on the right if there is an information bloc . The information bloc was set to an empty div. Therefore, as it is set, address was displayed on the right. opw-6334130 Forward-Port-Of: odoo/odoo#275771 Forward-Port-Of: odoo/odoo#273418
Before this commit, the journal and the memo of a payment linked to a company-paid expense report could be modified although such payments must be kept consistent with their expense report: a missing comma in the set of protected fields merged 'journal_id' and 'ref' into a single meaningless entry. The memo was also left editable because the set still referred to 'ref', which was renamed to 'memo'. Steps to reproduce: - submit, approve and post an expense paid by company - open the payment
Original PR description
Before this commit, the journal and the memo of a payment linked to a company-paid expense report could be modified although such payments must be kept consistent with their expense report: a missing…
Before this commit, the journal and the memo of a payment linked to a company-paid expense report could be modified although such payments must be kept consistent with their expense report: a missing comma in the set of protected fields merged 'journal_id' and 'ref' into a single meaningless entry. The memo was also left editable because the set still referred to 'ref', which was renamed to 'memo'. Steps to reproduce: - submit, approve and post an expense paid by company - open the payment created for the expense report - edit the memo or the journal and save, then try to edit the date Editing the date is refused with "You cannot do this modification since the payment is linked to an expense report", while the memo and journal changes are silently accepted. Solution: Restore the missing comma and protect the renamed memo field. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277737 Forward-Port-Of: odoo/odoo#277423
The builder HOOT tests were flaky when run as a suite while passing in isolation: - @website/builder/images: "Should format an image to be 800px", "should set the quality of an image to 50", and the gif/svg "Correct options appear..." tests, - @html_builder/image: "Size should not be displayed on CORS protected images". All failed the same way: a `contains(":iframe ... img")` click found the img but "0 visible elements" after 200ms, i.e. the image never got pixels in time. The images of t
Original PR description
The builder HOOT tests were flaky when run as a suite while passing in isolation: - @website/builder/images: "Should format an image to be 800px", "should set the quality of an image to 50", and the…
The builder HOOT tests were flaky when run as a suite while passing in isolation:
- @website/builder/images: "Should format an image to be 800px", "should set the quality of an image to 50", and the gif/svg "Correct options appear..." tests,
- @html_builder/image: "Size should not be displayed on CORS protected images".
All failed the same way: a `contains(":iframe ... img")` click found the img but "0 visible elements" after 200ms, i.e. the image never got pixels in time. The images of those tests are loaded by the browser from the *real* test server (element loads cannot be mocked by HOOT), and the requests were stuck for seconds behind other requests started by earlier tests and never awaited:
- test fixtures used made-up snippet thumbnails (data-oe-thumbnail="a.svg", or none at all, rendering "background-image: url(undefined)"). Relative to the test runner page, these resolve to /web/a.svg, /web/undefined... and each triggers a full website 404 page rendering on the server (~90 queries, taking seconds under load). One full @html_builder run produced 71 such requests, some taking up to 17s, starving the browser's connection pool.
- the mock of /html_editor/modify_image in "Save image with correct parameter" returned the obsolete {image_src, access_token, public} shape; saveModifiedImage reads newAttachmentUrls["original"], so the saved img src became the literal string "undefined" -> GET /web/undefined.
- the mocked attachment creations in the pasted/dropped image tests returned made-up URLs (/test_image_url.png, /url_image-1.png) that the editor sets as img src on save -> more expensive 404s.
Fix:
- don't render a background-image at all when a snippet has no thumbnail (also avoids the bogus url(undefined) request outside of tests),
- use a data URI as thumbnail in the default test fixtures,
- return the correct modify_image response shape, and existing static images (served in milliseconds) for the mocked attachment URLs,
- give the CORS-protected test image explicit width/height so that its visibility (checked before clicking it) does not depend on the server's response time at all.
Note that these failures predate the owl v3.0.0-alpha.44 update (they reproduce identically on the commit before it): repeatedly running the full suites while investigating the update's fallout simply surfaced them.
@html_builder went from 71 to 7 stray 404s (the few remaining come from fixtures whose thumbnail names are asserted on, they are harmless in isolation), and both @html_builder (395 tests) and @website/builder (557 tests) suites now pass reliably.
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-prMiscellaneous changes
Backport of #275640 Despite resolving the conflicts (file moved) this version also checks the python version since PyUnstable_Type_AssignVersionTag does not exists in python 3.10 To be safer, the whole logic is skipped if python < 3.13 Forward-Port-Of: odoo/odoo#277697
Original PR description
Backport of #275640 Despite resolving the conflicts (file moved) this version also checks the python version since PyUnstable_Type_AssignVersionTag does not exists in python 3.10 To be safer, the whole logic is skipped if python < 3.13 Forward-Port-Of: odoo/odoo#277697
Before this commit, calls to the route `/shop?search=<search_term>` would lead the search for `product_public_categories` to use a query in the shape of `product_id in (<list_of_ids>)`. In the case where the cardinality of the product table becomes large (> 10k products), if `search_term` is very broad-spectrum, the length of `list_of_ids` reaches the size of the product table. In that case the query generated to search for categories becomes significantly slow to parse (> 14 seconds in our te
Original PR description
Before this commit, calls to the route `/shop?search=<search_term>` would lead the search for `product_public_categories` to use a query in the shape of `product_id in (<list_of_ids>)`. In the case…
Before this commit, calls to the route `/shop?search=<search_term>` would lead the search for `product_public_categories` to use a query in the shape of `product_id in (<list_of_ids>)`. In the case where the cardinality of the product table becomes large (> 10k products), if `search_term` is very broad-spectrum, the length of `list_of_ids` reaches the size of the product table. In that case the query generated to search for categories becomes significantly slow to parse (> 14 seconds in our tests). This commit proposes as an alternative to resort to a sub-query to fetch the product ids that are relevant in the context of `product_public_categories`. Because of how the list of products is acquired initially, we can't rely on the `_search()` method to generate the sub-query. The following table shows average gains for "increasing search term specificity". Here, "specificity" is determined by the amount of characters in the search term and the related number of hits expected from the search. ### Cardinality ~250k records | Metric | ~228,872 hits | ~2,870 hits | ~377 hits | ~11 hits | | :--- | :--- | :--- | :--- | :--- | | Before Fix | 14.027s | 5.726s | 3.183s | 3.139s | | After Fix | 1.216s | 3.794s* | 1.330s | 1.301s | ### Cardinality 10k records | Metric | 8,897 hits | 1,122 hits | 15 hits | 0 hits | | :--- | :--- | :--- | :--- | :--- | | Before Fix | 1.386s | 3.232s* | 0.580s | 0.395s | | After Fix | 0.756s | 3.410s* | 0.772s | 0.572s | *Note: The increase in response time in the second column is caused by a different execution path taken (fuzzy search) which becomes the most significant path in terms of execution time once the other queries are optimized. opw-6299343 Forward-Port-Of: odoo/odoo#275306 Forward-Port-Of: odoo/odoo#271306
16 changes
Resolved issues and error corrections
The context variable skip_is_manually_modified needs to be passed in order for the autoposting feature to work. The is_manually_modified variable of the move needs to evaluate to true Fixes error in test TestInvoiceExtract.test_autopost_bills_ocr for mc and fr localizations Related pr: https://github.com/odoo/odoo/pull/271865 runbot-6369932 Forward-Port-Of: odoo/odoo#276953
Original PR description
The context variable skip_is_manually_modified needs to be passed in order for the autoposting feature to work. The is_manually_modified variable of the move needs to evaluate to true Fixes error in test TestInvoiceExtract.test_autopost_bills_ocr for mc and fr localizations Related pr: https://github.com/odoo/odoo/pull/271865 runbot-6369932 Forward-Port-Of: odoo/odoo#276953
## Problem When generating accrual entries for multiple sale orders, the stock variation lines would all show the same order name, even if the line belonged to a different sale order. This is caused by the `order` variable being reused from a previous loop. ## Solution We will pull the order name directly from the order line in the current iteration. ## Steps to reproduce (Runbot v19) 1. Create a product with AVCO perpetual valuation 2. Make sure all accounts are configured properly (I
Original PR description
## Problem When generating accrual entries for multiple sale orders, the stock variation lines would all show the same order name, even if the line belonged to a different sale order. This is caused…
## Problem When generating accrual entries for multiple sale orders, the stock variation lines would all show the same order name, even if the line belonged to a different sale order. This is caused by the `order` variable being reused from a previous loop. ## Solution We will pull the order name directly from the order line in the current iteration. ## Steps to reproduce (Runbot v19) 1. Create a product with AVCO perpetual valuation 2. Make sure all accounts are configured properly (Income, Expense, Stock, and stock variation accounts) 3. Add units to the stock (it can be with an adjustment, as long as the product has a cost already set) 4. Create 2 separate sales orders for this product 5. Deliver both of the sales orders, do not invoice them 6. Now go to the Accounting App Review>Invoices to be issued 7. Select the 2 invoices that were created. The Revenue accrual lines are correct, with each SO being referenced, but on the Stock variation lines, only the last SO selected will appear. opw-6361032 Forward-Port-Of: odoo/odoo#277058
# Step to reproduce - Install eCommerce - Activate dev mode with tests assets (important!) - Go to the website & add a Countdow in the footer - Add a new product from the website system tray - Put any name & Save - Go into Edit mode - In the Style tab, (un)toggle "Tax Indication" (may need to do it multiple times) > Note that the issue is quite inconsistent to reproduce # Issue A traceback is shown # Cause The only thing I'm sure of is that the error is caused by this code : htt
Original PR description
# Step to reproduce - Install eCommerce - Activate dev mode with tests assets (important!) - Go to the website & add a Countdow in the footer - Add a new product from the website system tray - Put…
# Step to reproduce - Install eCommerce - Activate dev mode with tests assets (important!) - Go to the website & add a Countdow in the footer - Add a new product from the website system tray - Put any name & Save - Go into Edit mode - In the Style tab, (un)toggle "Tax Indication" (may need to do it multiple times) > Note that the issue is quite inconsistent to reproduce # Issue A traceback is shown # Cause The only thing I'm sure of is that the error is caused by this code : https://github.com/odoo/odoo/blob/8759429547e42e9f63b15a7c80475be46ef437e2/addons/website/static/tests/tour_utils/lifecycle_dep_interaction.js#L18-L20 And that it is linked to `browser.localStorage`. I suspect it is due to some weird localStorage and WysiwygAdapter interaction : https://github.com/odoo/odoo/blob/d6a08b67a948f569a1ca893b6337ce50b4ef9f07/addons/website/static/tests/tours/widget_lifecycle.js#L53-L60 But I can't be sure because debugging tools do not seem to be working. See the inverstigation comment in the associated PR for more information. # Proposed Solution Since this code is only used for this test : https://github.com/odoo/odoo/blob/96a0a9a0332ae460973b6f01b461a0f7e3e2f7fa/addons/website/static/tests/tours/interaction_lifecycle.js#L14-L15 And the test directly parses from the `window.localStorage` : https://github.com/odoo/odoo/blob/96a0a9a0332ae460973b6f01b461a0f7e3e2f7fa/addons/website/static/tests/tours/interaction_lifecycle.js#L50 We can use `window.localStorage` instead of `browser.localStorage` as it fixes the issue opw-6246850 Forward-Port-Of: odoo/odoo#272736
Issue :- Steps to Reproducet: SaaS 19.3 - Create a new database Install the Sale module. - Create a product set some On Hand quantity for that product (via Inventory adjustment). - Create a Quotation using that product. - Confirm the quotation (turning it into a Sales Order). - Open the Forecasted Report for that product. The Reserve / Unreserve button in the Forecasted Report not render. <img width="1811" height="323" alt="image" src="https://github.com/user-attachments/assets/4093b
Original PR description
Issue :- Steps to Reproducet: SaaS 19.3 - Create a new database Install the Sale module. - Create a product set some On Hand quantity for that product (via Inventory adjustment). - Create a Quotation…
Issue :-
Steps to Reproducet: SaaS 19.3
- Create a new database Install the Sale module.
- Create a product set some On Hand quantity for that product (via Inventory adjustment).
- Create a Quotation using that product.
- Confirm the quotation (turning it into a Sales Order).
- Open the Forecasted Report for that product.
The Reserve / Unreserve button in the Forecasted Report not render.
<img width="1811" height="323" alt="image" src="https://github.com/user-attachments/assets/4093bddb-f332-4b84-a482-a6604ebcb318" />
Regression from the OWL3 rendering context migration ("[REF] stock,*: run rendering context migration script"), which rewrote the template call `displayReserve(line)` into `this.displayReserve(line)`. https://github.com/odoo/odoo/commit/df40bc9e261a62c045e7e6150a60663a582e7dae and it comes in 19.2 onwards version.
The previous bare call compiled to `ctx['displayReserve'](...)`, so the method executed with `this` bound to that render context, which does own `line` and `line_index`. The lookups resolved by accident, not by design. as far as i have known.
With the explicit [`this.`](https://github.com/odoo/odoo/commit/df40bc9e261a62c045e7e6150a60663a582e7dae#diff-c556e01f9a3ebdb27bb6599d12b74c7bb0a433177cc0e126365cb763a874d9f4R81) form required by OWL3, `this` is correctly the component instance, so `this.line` and `this.line_index` are undefined:
```py
- `this.line_index - 1 >= 0` -> NaN >= 0 -> false, the block is
skipped and `splittedLine` stays true
- `this.lines[this.line_index]` -> undefined
- `.includes(undefined)` -> false, so `isOnHand()` is false
```
<img width="1404" height="786" alt="image" src="https://github.com/user-attachments/assets/6d2cb88b-a695-4388-9b5e-3eac266f1877" />
`displayReserve()` therefore always returns a falsy value and the `t-if` never renders the button. `isOnHand(line)`, which the template also calls directly to render the reservable quantity, is broken for the same reason.
Root cause:
loop variables produced by `t-foreach`/`t-as` live only on the template render context and must never be read off `this` in a component method. The previous code depended on OWL2 resolving a bare template call against that context, which OWL3 no longer does.
``` with the displayReserve(line) ```
<img width="1185" height="599" alt="image" src="https://github.com/user-attachments/assets/ed79f6db-f95c-437f-baf8-f65391df14e7" />
```with the this.displayReserve(line)```
<img width="1020" height="641" alt="image" src="https://github.com/user-attachments/assets/61103db5-7e0a-4362-9dd4-c2f47db2bd97" />
Fix:
derive the values from the `line` argument the methods already receive, instead of reading them off `this`.
```py
- `displayReserve()`: `const line_index = this.lines.indexOf(line)`, and
use the `line` argument in place of `this.line`
- `isOnHand()` / `isReconciled()`: test against `line` directly, since
`this.lines[line_index] === line` inside the loop
```
The template is unchanged: the OWL3-compliant `this.displayReserve(line)` call stays as the migration left it, and no method signature changes.
``` with the current fix```
<img width="1100" height="480" alt="image" src="https://github.com/user-attachments/assets/39147abb-ba5e-42ae-84f5-3d7cbadda1e1" />
<img width="1879" height="304" alt="image" src="https://github.com/user-attachments/assets/fafd3d6a-7591-4dbd-a85c-8fb9de541dd8" />
OPW:- 6363290
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-prIssue: The unreserve button in forecast is no longer visible. Steps to Reproduce: 1. Create an MO for a product that has a storable component 2. Confirm the MO 3. Go to the component product form 4. Click on the forecast smart button Cause: After this commit, https://github.com/odoo/odoo/commit/df40bc9e261a62c045e7e6150a60663a582e7dae to support Owl3, the code was breaking because we were no longer passing line_index through `this`. Solution: Since the variable `line_index` was n
Original PR description
Issue: The unreserve button in forecast is no longer visible. Steps to Reproduce: 1. Create an MO for a product that has a storable component 2. Confirm the MO 3. Go to the component product form 4. Click on the forecast smart button Cause: After this commit, https://github.com/odoo/odoo/commit/df40bc9e261a62c045e7e6150a60663a582e7dae to support Owl3, the code was breaking because we were no longer passing line_index through `this`. Solution: Since the variable `line_index` was no longer available with `this`, we are now passing it as a parameter. opw-6317760
Steps to reproduce: - Install `project`, open a project and switch to the Gantt view - Start dragging a task while holding Ctrl (copy mode), then switch browser tab with Ctrl+Tab (or Ctrl+Shift+Tab, Ctrl+PgUp/PgDn) - Come back to the Gantt tab and drop the task without holding Ctrl Issue: The task is duplicated instead of rescheduled. Cause: The copy/reschedule behavior is tracked through window keydown/keyup listeners on the Control key. While the document is hidden, the keyup for Co
Original PR description
Steps to reproduce: - Install `project`, open a project and switch to the Gantt view - Start dragging a task while holding Ctrl (copy mode), then switch browser tab with Ctrl+Tab (or Ctrl+Shift+Tab,…
Steps to reproduce: - Install `project`, open a project and switch to the Gantt view - Start dragging a task while holding Ctrl (copy mode), then switch browser tab with Ctrl+Tab (or Ctrl+Shift+Tab, Ctrl+PgUp/PgDn) - Come back to the Gantt tab and drop the task without holding Ctrl Issue: The task is duplicated instead of rescheduled. Cause: The copy/reschedule behavior is tracked through window keydown/keyup listeners on the Control key. While the document is hidden, the keyup for Control is never received, so the drag sequence resumes with a stale "Ctrl pressed" state and the drop is treated as a copy. Fix: Keyboard and pointer states cannot be reliably tracked while the document is hidden, so cancel any ongoing drag sequence from `makeDraggableHook` as soon as the tab is no longer visible (through the `visibilitychange` event). This applies to every drag and drop instance built on the hook builder. opw-6298440 Forward-Port-Of: odoo/odoo#277014 Forward-Port-Of: odoo/odoo#276859
Before this fix, if a custom group was added in an Odoo PIVOT in a spreadsheet, without sorting, the custom group name was added to the RPC kwards.order, causing a server error. After this fix, the custom group name is removed from the RPC kwards.order. Task: 6401442 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277478
Original PR description
Before this fix, if a custom group was added in an Odoo PIVOT in a spreadsheet, without sorting, the custom group name was added to the RPC kwards.order, causing a server error. After this fix, the custom group name is removed from the RPC kwards.order. Task: 6401442 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277478
Note: In odoo all date/datetime fields are stored and computed by default as UTC Before this commit, dates were called using local timezone getters. This caused the time returned from web to be shifted by the timezone as the dates returned would be treated as UTC. After this commit, dates are now called using UTC timzone getters. Now all web times are retrived as UTC and in sync with the rest of the odoo fields and computations. task-6271421 Forward-Port-Of: odoo/odoo#276683 Forward-Po
Original PR description
Note: In odoo all date/datetime fields are stored and computed by default as UTC Before this commit, dates were called using local timezone getters. This caused the time returned from web to be shifted by the timezone as the dates returned would be treated as UTC. After this commit, dates are now called using UTC timzone getters. Now all web times are retrived as UTC and in sync with the rest of the odoo fields and computations. task-6271421 Forward-Port-Of: odoo/odoo#276683 Forward-Port-Of: odoo/odoo#265250
v19 WIoT Boxes will be listening on localhost when updating to v19.1+, we need to ensure they use `http_interface = 0.0.0.0` after the update. Forward-Port-Of: odoo/odoo#276655 Forward-Port-Of: odoo/odoo#272063
Original PR description
v19 WIoT Boxes will be listening on localhost when updating to v19.1+, we need to ensure they use `http_interface = 0.0.0.0` after the update. Forward-Port-Of: odoo/odoo#276655 Forward-Port-Of: odoo/odoo#272063
The footer slideout state was computed only once during interaction setup. If the main content height changed afterward, e.g. in edit mode: dropping or removing snippets, or resizing the window, the effect could remain enabled/disabled even though the content had become taller/shorter than the viewport. Steps to reproduce: - Go into edit mode - Add two snippets on the page - On the footer, set the "Slideout Effect" option to "Slide Hover" - Remove one snippet - Half of the footer is
Original PR description
The footer slideout state was computed only once during interaction setup. If the main content height changed afterward, e.g. in edit mode: dropping or removing snippets, or resizing the window, the effect could remain enabled/disabled even though the content had become taller/shorter than the viewport. Steps to reproduce: - Go into edit mode - Add two snippets on the page - On the footer, set the "Slideout Effect" option to "Slide Hover" - Remove one snippet - Half of the footer is hidden by the hover effect, which should not happen task-6117257 Forward-Port-Of: odoo/odoo#277614 Forward-Port-Of: odoo/odoo#275291
**Description of the issue/feature this PR addresses:** ---------------------------------------------- On mobile devices, the meeting view had two UI issues affecting the call experience. The call permission dialog could display an unwanted focus outline around its content because the dialog body was focused on touch devices. Additionally, meeting action buttons could be partially hidden, especially in portrait mode, as the meeting view could extend beyond the visible viewport height.
Original PR description
**Description of the issue/feature this PR addresses:** ---------------------------------------------- On mobile devices, the meeting view had two UI issues affecting the call experience. The call…
**Description of the issue/feature this PR addresses:** ---------------------------------------------- On mobile devices, the meeting view had two UI issues affecting the call experience. The call permission dialog could display an unwanted focus outline around its content because the dialog body was focused on touch devices. Additionally, meeting action buttons could be partially hidden, especially in portrait mode, as the meeting view could extend beyond the visible viewport height. **Current behavior before PR:** ---------------------------------------------- - Opening the call permission dialog on mobile could show an unwanted focus outline around the dialog content - Meeting action buttons could be partially hidden on mobile devices - In portrait mode, the footer could overflow below the visible viewport **Desired behavior after PR is merged:** ---------------------------------------------- - Call permission dialog opens on mobile without showing the unwanted focus outline on main body. - Meeting action buttons remain fully visible on mobile devices Task-6232825 ---------------------------------------------- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#266620
**Steps to reproduce:** * Install l10n_fr. * Create an invoice using a tax with the E3 tax grid. * Post the invoice so it is included in the tax report. * Open the French tax report. **Observed Behaviour:** The E3 line is blank even though the amount is present in the report data. The amount is recorded as a negative value, while the report formula expects a positive value, causing it to be deducted from the report total. **Cause:** The E3 tax report expression used the for
Original PR description
**Steps to reproduce:** * Install l10n_fr. * Create an invoice using a tax with the E3 tax grid. * Post the invoice so it is included in the tax report. * Open the French tax report. **Observed Behaviour:** The E3 line is blank even though the amount is present in the report data. The amount is recorded as a negative value, while the report formula expects a positive value, causing it to be deducted from the report total. **Cause:** The E3 tax report expression used the formula E3, which does not account for tax grid amounts stored as negative values. **Fix:** Update the E3 report expression formula from E3 to -E3 so that negative E3 amounts are correctly displayed in the tax report. opw - 6321790 Forward-Port-Of: odoo/odoo#274052
Calling the method in RPC causes an error: ``` TypeError: cannot marshal None unless allow_none is enabled ``` 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#277047 Forward-Port-Of: odoo/odoo#276541
Original PR description
Calling the method in RPC causes an error: ``` TypeError: cannot marshal None unless allow_none is enabled ``` 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#277047 Forward-Port-Of: odoo/odoo#276541
Before this commit, the res.users model was not being loaded in the POS when reloading data. If user A was logged in and then on the same device user B logged in, it would not load the new user B data, and it causes user B to not be able to go to the backend. opw-6388954 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276546
Original PR description
Before this commit, the res.users model was not being loaded in the POS when reloading data. If user A was logged in and then on the same device user B logged in, it would not load the new user B data, and it causes user B to not be able to go to the backend. opw-6388954 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276546
Issue: On an invoice PDF, using a layout with the address on the left. If a contact has a delivery address, but the option "Customer address" is not set, address will be displayed on the right instead of the left. Steps to reproduce: - Create a customer - Add a Delivery address to the customer - Ensure "Customer Address" is not set in the settings - Choose a layout with the address on the left (bubble, wave, ...) - Create an invoice to the customer - print the PDF Current behavior:
Original PR description
Issue: On an invoice PDF, using a layout with the address on the left. If a contact has a delivery address, but the option "Customer address" is not set, address will be displayed on the right instead of the left. Steps to reproduce: - Create a customer - Add a Delivery address to the customer - Ensure "Customer Address" is not set in the settings - Choose a layout with the address on the left (bubble, wave, ...) - Create an invoice to the customer - print the PDF Current behavior: - Customer address is on the right Expected behavior: - Customer address is on the left Cause: Address is displayed on the right if there is an information bloc . The information bloc was set to an empty div. Therefore, as it is set, address was displayed on the right. opw-6334130 Forward-Port-Of: odoo/odoo#275771 Forward-Port-Of: odoo/odoo#273418
Before this commit, the journal and the memo of a payment linked to a company-paid expense report could be modified although such payments must be kept consistent with their expense report: a missing comma in the set of protected fields merged 'journal_id' and 'ref' into a single meaningless entry. The memo was also left editable because the set still referred to 'ref', which was renamed to 'memo'. Steps to reproduce: - submit, approve and post an expense paid by company - open the payment
Original PR description
Before this commit, the journal and the memo of a payment linked to a company-paid expense report could be modified although such payments must be kept consistent with their expense report: a missing…
Before this commit, the journal and the memo of a payment linked to a company-paid expense report could be modified although such payments must be kept consistent with their expense report: a missing comma in the set of protected fields merged 'journal_id' and 'ref' into a single meaningless entry. The memo was also left editable because the set still referred to 'ref', which was renamed to 'memo'. Steps to reproduce: - submit, approve and post an expense paid by company - open the payment created for the expense report - edit the memo or the journal and save, then try to edit the date Editing the date is refused with "You cannot do this modification since the payment is linked to an expense report", while the memo and journal changes are silently accepted. Solution: Restore the missing comma and protect the renamed memo field. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277737 Forward-Port-Of: odoo/odoo#277423
15 changes
Enhancements to existing features
Since [website builder refactor], a date field or a datetime that appears in the page is not editable from website builder. This commit re-introduces the ability to do so. [website builder refactor]: 9fe45e2b7ddbbfd0445ffe25a859e67a316d02b2 task-6230582 Forward-Port-Of: odoo/odoo#277408 Forward-Port-Of: odoo/odoo#270325
Original PR description
Since [website builder refactor], a date field or a datetime that appears in the page is not editable from website builder. This commit re-introduces the ability to do so. [website builder refactor]: 9fe45e2b7ddbbfd0445ffe25a859e67a316d02b2 task-6230582 Forward-Port-Of: odoo/odoo#277408 Forward-Port-Of: odoo/odoo#270325
Resolved issues and error corrections
Steps to reproduce: - Install `project`, open a project and switch to the Gantt view - Start dragging a task while holding Ctrl (copy mode), then switch browser tab with Ctrl+Tab (or Ctrl+Shift+Tab, Ctrl+PgUp/PgDn) - Come back to the Gantt tab and drop the task without holding Ctrl Issue: The task is duplicated instead of rescheduled. Cause: The copy/reschedule behavior is tracked through window keydown/keyup listeners on the Control key. While the document is hidden, the keyup for Co
Original PR description
Steps to reproduce: - Install `project`, open a project and switch to the Gantt view - Start dragging a task while holding Ctrl (copy mode), then switch browser tab with Ctrl+Tab (or Ctrl+Shift+Tab, Ctrl+PgUp/PgDn) - Come back to the Gantt tab and drop the task without holding Ctrl Issue: The task is duplicated instead of rescheduled. Cause: The copy/reschedule behavior is tracked through window keydown/keyup listeners on the Control key. While the document is hidden, the keyup for Control is never received, so the drag sequence resumes with a stale "Ctrl pressed" state and the drop is treated as a copy. Fix: Keyboard and pointer states cannot be reliably tracked while the document is hidden, so cancel any ongoing drag sequence from `makeDraggableHook` as soon as the tab is no longer visible (through the `visibilitychange` event). This applies to every drag and drop instance built on the hook builder. opw-6298440 Forward-Port-Of: odoo/odoo#276859
**Steps to reproduce:** 1. Create a Sales Order. 2. Create a 50% down payment invoice. 3. Create a credit note for the down payment invoice. 4. Reset the credit note to Draft and cancel it. 5. Create the final invoice from the Sales Order. **Issue:** The final invoice is generated for 100% of the order amount, acting as if the down payment invoice does not exist. **Expected behavior:** The final invoice should only include the remaining 50% of the order amount because a valid 50% do
Original PR description
**Steps to reproduce:** 1. Create a Sales Order. 2. Create a 50% down payment invoice. 3. Create a credit note for the down payment invoice. 4. Reset the credit note to Draft and cancel it. 5. Create…
**Steps to reproduce:** 1. Create a Sales Order. 2. Create a 50% down payment invoice. 3. Create a credit note for the down payment invoice. 4. Reset the credit note to Draft and cancel it. 5. Create the final invoice from the Sales Order. **Issue:** The final invoice is generated for 100% of the order amount, acting as if the down payment invoice does not exist. **Expected behavior:** The final invoice should only include the remaining 50% of the order amount because a valid 50% down payment invoice still exists. **Why this happens:** - The `price_unit` on the Sales Order's down payment line is manually updated during `action_post()` based on the sum of posted invoices minus posted credit notes. - When the credit note is posted, `price_unit` drops to 0. However, when that credit note is subsequently reset to draft and cancelled, it triggers `button_cancel()` which only refreshed the line's display name and failed to recalculate `price_unit`. As a result, `price_unit` remained at 0 even though the credit note was no longer active, causing the final invoice to deduct nothing. opw-6373578 Forward-Port-Of: odoo/odoo#277043 Forward-Port-Of: odoo/odoo#275684
Before this commit, when changing the Tip product in the POS settings, the change was reverted and the default Tip product was used instead. opw-6366774 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
Before this commit, when changing the Tip product in the POS settings, the change was reverted and the default Tip product was used instead. opw-6366774 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Steps to reproduce: - Install Argentina(l10n_ar) localization > Change Company - Accounting > Customers > Invoices > Select an invoice > Click "Pay" - In "Journal" select "Third Party Checks" > In "Payment Method" select "New Third Party Checks" > Fill the rest of the check info (Number, Bank Account, Issuer Vat, Payment Date and Amount) > Click on "Create Payment" - Repeat the payment process for another invoice with same info > Validation Error A change in [PR] caused the check uniquene
Original PR description
Steps to reproduce: - Install Argentina(l10n_ar) localization > Change Company - Accounting > Customers > Invoices > Select an invoice > Click "Pay" - In "Journal" select "Third Party Checks" > In…
Steps to reproduce: - Install Argentina(l10n_ar) localization > Change Company - Accounting > Customers > Invoices > Select an invoice > Click "Pay" - In "Journal" select "Third Party Checks" > In "Payment Method" select "New Third Party Checks" > Fill the rest of the check info (Number, Bank Account, Issuer Vat, Payment Date and Amount) > Click on "Create Payment" - Repeat the payment process for another invoice with same info > Validation Error A change in [PR] caused the check uniqueness constraint apply to all checks. Because of this, using the same check number with the "New Third Party Checks" payment method now raises a validation error. This is not the intended behavior. The uniqueness constraint should only apply to "Own Checks" when using a "Bank" journal for Vendor Bills. It should not apply to "Third Party Checks" with the "New Third Party Checks" payment method in Customer Invoice. Avoid linking `l10n_latam_check_ids` on liquidity lines for outbound "Own Checks" payments so that the uniqueness constraint is enforced only for the "Vendor Bills". [PR]: https://github.com/odoo/odoo/pull/243509/changes opw-6334965 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
**Steps to reproduce:** Both problem are reproducible on runbot aswell but for more clarity (and for empty accounting), those steps are on a fresh db with no demo data Problem 1 : - create a new db with stock_account, purchase and accountant - In the companies view, select your company - in the branch tab, create a branch for your company - for both the branch and the company, in the settings set the valuation as periodic daily With only the branch company selected: - create
Original PR description
**Steps to reproduce:** Both problem are reproducible on runbot aswell but for more clarity (and for empty accounting), those steps are on a fresh db with no demo data Problem 1 : - create a new db…
**Steps to reproduce:** Both problem are reproducible on runbot aswell but for more clarity (and for empty accounting), those steps are on a fresh db with no demo data Problem 1 : - create a new db with stock_account, purchase and accountant - In the companies view, select your company - in the branch tab, create a branch for your company - for both the branch and the company, in the settings set the valuation as periodic daily With only the branch company selected: - create a warehouse for your branch - create a storable prod with a cost of 10 - validate a receipt for 1 unit of the prod - open inventory valuation view and check that there is variation lines for 10 - open 'scheduled actions' view - select 'inventory valuation closing' - click on 'run manually' With the main company selected: - Open journal items - click on the journal entry of any of the move line with label 'closing stock variation global for company [branch]' - select the 'other info' tab Problem 2: - create a new db with stock_account, purchase and accountant - create a company 2 - for both companies, in the settings set the valuation as periodic daily With company 2 selected - create a warehouse for company 2 - in the settings for fiscal localization set the 'generic chart of account' - create a storable product with a cost of 10 - validate a receipt for 1 quantity of the product - open inventory valuation view and check that there is variation lines for 10 - open 'scheduled actions' view - select 'inventory valuation closing' - click on 'run manually' **Current behavior:** Problem 1: the company of the account move is the main company Problem 2: There is a traceback including 'UserError: Everything is correctly closed' **Expected behavior:** Problem 1: It should be the branch company Problem 2: Everything is closed in company 1, but it shouldn't prevent to generate the entries for company 2 **Cause of the issue:** Problem 1: Inside _cron_post_stock_valuation we call action_close_stock_valuation for each company (if periodic daily or periodic monthly and we're the last day of the month) https://github.com/odoo/odoo/blob/b8e5291d103d9f43bd8db6d2dfe708076a57ea37/addons/stock_account/models/res_company.py#L143-L144 Inside action_close_stock_valuation when creating the account move we add a context to be sure that the move is created for the main company selected https://github.com/odoo/odoo/blob/b8e5291d103d9f43bd8db6d2dfe708076a57ea37/addons/stock_account/models/res_company.py#L72 The fix comes from this PR https://github.com/odoo/odoo/pull/263828 and was improved starting from 19.1 to simply add a the company_id on the moves_vals. But the problem is that this fix failed to consider the case where we come from cron because in this case self.env.company is the main company of the user, which is a problem because as we iterate through the companies we want each account move to be created for its own company. This other PR https://github.com/odoo/odoo/pull/269152 corrects this by using self.id instead of self.company.id but only starting from 19.1. The fix is essentially a back port of those 2 PR. Problem 2: When you call action_close_stock_valuation from _cron_post_stock_valuation for the company that has no inventory valuation and thus no account move to create we will raise the user error https://github.com/odoo/odoo/blob/b8e5291d103d9f43bd8db6d2dfe708076a57ea37/addons/stock_account/models/res_company.py#L58-L60 This makes sense if the method was called from the inventory valuation view. But in our case it's called from cron so we might also call it on other companies and therefore we don't want to raise an exception if there is no account move to create on one of the companies. opw-6144294 Forward-Port-Of: odoo/odoo#276771 Forward-Port-Of: odoo/odoo#275294
The context variable skip_is_manually_modified needs to be passed in order for the autoposting feature to work. The is_manually_modified variable of the move needs to evaluate to true Fixes error in test TestInvoiceExtract.test_autopost_bills_ocr for mc and fr localizations Related pr: https://github.com/odoo/odoo/pull/271865 runbot-6369932 Forward-Port-Of: odoo/odoo#276953
Original PR description
The context variable skip_is_manually_modified needs to be passed in order for the autoposting feature to work. The is_manually_modified variable of the move needs to evaluate to true Fixes error in test TestInvoiceExtract.test_autopost_bills_ocr for mc and fr localizations Related pr: https://github.com/odoo/odoo/pull/271865 runbot-6369932 Forward-Port-Of: odoo/odoo#276953
Issue: When a shopper pays for an online order entirely using a reward (e.g. a discount code covering 100% of the total), the order total is zero. With automatic invoicing enabled, an invoice with an amount of 0 is created. But, the 0 invoice is never emailed to the customer. Whereas, for orders where the total is more than 0, an invoice is created, then emailed to the customer. The customer should be emailed the invoice, even if its amount is 0. Steps to reproduce: 1. Enable automatic invo
Original PR description
Issue: When a shopper pays for an online order entirely using a reward (e.g. a discount code covering 100% of the total), the order total is zero. With automatic invoicing enabled, an invoice with an…
Issue: When a shopper pays for an online order entirely using a reward (e.g. a discount code covering 100% of the total), the order total is zero. With automatic invoicing enabled, an invoice with an amount of 0 is created. But, the 0 invoice is never emailed to the customer. Whereas, for orders where the total is more than 0, an invoice is created, then emailed to the customer. The customer should be emailed the invoice, even if its amount is 0. Steps to reproduce: 1. Enable automatic invoicing. 2. Create a code for a 100% discount. 3. As a shopper, add a product to cart on the website. 4. While checking out, apply the 100% discount code to the order. 5. Complete the checkout. 6. Confirm that an invoice was created and posted, but was not emailed to the customer. Explanation: Normally, order confirmation and invoicing are handled by the `_post_process` method on the `payment.transaction` model. With automatic invoicing enabled, `_post_process` confirms the sale order, creates the invoice, and sends the invoice via `_send_invoice` (another method on the `payment.transaction` model). If `sale.async_emails` is enabled, `_post_process` will trigger a cron that invokes `_send_invoice` instead of invoking it directly. When an order is fully covered by a reward, there's nothing to pay. In this case, no payment.transaction record is ever created, and `_post_process` never runs. Instead, the order is confirmed through the `_validate_order` method on the `sale.order` model. The `sale_loyalty` module extends `_validate_order` so that, with automatic invoicing enabled, it will create and post an invoice for zero-amount orders. But, nothing in this path ever calls `_send_invoice` or an equivalent. So, the invoice is created and posted but never sent. Solution: This adds logic for sending invoices to the extension of `_validate_order` in the `sale_loyalty` module. We mirror the logic used in `_send_invoice` in the `payment.transaction` model. Notes: There is duplicated code from `_send_invoice` in this fix. That is because `_send_invoice`, a method on the `payment.transaction` model, can't be used in this flow. A fix that avoids code duplication would require serious refactoring. This will never trigger a cron to send the invoice, even if `sale.async_emails` is enabled. That is because the cron invokes `_send_invoice`. Since fully reward-covered orders are probably not common, any performance benefits of using a cron are probably not significant. But, making a new cron to be used in this case is also an option. opw-6363334 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275750 Forward-Port-Of: odoo/odoo#275190
# Step to reproduce - Install eCommerce - Activate dev mode with tests assets (important!) - Go to the website & add a Countdow in the footer - Add a new product from the website system tray - Put any name & Save - Go into Edit mode - In the Style tab, (un)toggle "Tax Indication" (may need to do it multiple times) > Note that the issue is quite inconsistent to reproduce # Issue A traceback is shown # Cause The only thing I'm sure of is that the error is caused by this code : htt
Original PR description
# Step to reproduce - Install eCommerce - Activate dev mode with tests assets (important!) - Go to the website & add a Countdow in the footer - Add a new product from the website system tray - Put…
# Step to reproduce - Install eCommerce - Activate dev mode with tests assets (important!) - Go to the website & add a Countdow in the footer - Add a new product from the website system tray - Put any name & Save - Go into Edit mode - In the Style tab, (un)toggle "Tax Indication" (may need to do it multiple times) > Note that the issue is quite inconsistent to reproduce # Issue A traceback is shown # Cause The only thing I'm sure of is that the error is caused by this code : https://github.com/odoo/odoo/blob/8759429547e42e9f63b15a7c80475be46ef437e2/addons/website/static/tests/tour_utils/lifecycle_dep_interaction.js#L18-L20 And that it is linked to `browser.localStorage`. I suspect it is due to some weird localStorage and WysiwygAdapter interaction : https://github.com/odoo/odoo/blob/d6a08b67a948f569a1ca893b6337ce50b4ef9f07/addons/website/static/tests/tours/widget_lifecycle.js#L53-L60 But I can't be sure because debugging tools do not seem to be working. See the inverstigation comment in the associated PR for more information. # Proposed Solution Since this code is only used for this test : https://github.com/odoo/odoo/blob/96a0a9a0332ae460973b6f01b461a0f7e3e2f7fa/addons/website/static/tests/tours/interaction_lifecycle.js#L14-L15 And the test directly parses from the `window.localStorage` : https://github.com/odoo/odoo/blob/96a0a9a0332ae460973b6f01b461a0f7e3e2f7fa/addons/website/static/tests/tours/interaction_lifecycle.js#L50 We can use `window.localStorage` instead of `browser.localStorage` as it fixes the issue opw-6246850 Forward-Port-Of: odoo/odoo#272736
The translate button next to a translatable field saves the record before opening the translation dialog for its id. Since https://github.com/odoo/odoo/commit/a85ca9679e3855936afc66b034d05d75f672dd26 it saves record.model.root rather than the record itself. When the field belongs to a new record still edited inside an x2many, for example an answer added in the survey question popup, saving the root only saves the parent and the new line keeps no database id. The dialog then opens with the id set
Original PR description
The translate button next to a translatable field saves the record before opening the translation dialog for its id. Since https://github.com/odoo/odoo/commit/a85ca9679e3855936afc66b034d05d75f672dd26…
The translate button next to a translatable field saves the record before opening the translation dialog for its id. Since https://github.com/odoo/odoo/commit/a85ca9679e3855936afc66b034d05d75f672dd26 it saves record.model.root rather than the record itself. When the field belongs to a new record still edited inside an x2many, for example an answer added in the survey question popup, saving the root only saves the parent and the new line keeps no database id. The dialog then opens with the id set to false and calls update_field_translations on it, which builds WHERE id = false and the database rejects it with operator does not exist: integer = boolean. Such a record gets no id of its own, and after a save and reload there is no reliable way to match the saved line back to the one that was clicked, so the dialog can never open for it. A canTranslate getter in TranslationButton returns false for a new record whose model root is another record, which is exactly a line still edited inside an x2many, and the template only renders the button when it is true. The variant in editable lists, where model.root is a list rather than a record, was handled in https://github.com/odoo/odoo/commit/cb34b318004c3ca9db755d8dbbad429609220df3. Steps to reproduce: 1. Activate a second language in Settings > Translations > Languages 2. Open the Surveys app and create a survey 3. Add a question, then in the Answers tab add a line and type a value 4. Click the EN button next to the answer, fill the second language, and Save => RPC error operator does not exist: integer = boolean from WHERE id = false Ticket [link](https://www.odoo.com/odoo/project.task/6260427) opw-6260427 Forward-Port-Of: odoo/odoo#270635 Forward-Port-Of: odoo/odoo#267781
**Steps to reproduce:** - Create an attribute of type always, 2 values A and B for it - The two values should have an extra price, like 100 for A and 150 for B - Create an attribute of type dynamic, 2 values C and D for it - C should have an extra price of 100 and 150 for D - Make a product with both of those product, set the price to 100 2 possibilities: - In the PoS, click the product, on the product popup, the price is 100 - This 100 is the product's price and does not change ev
Original PR description
**Steps to reproduce:** - Create an attribute of type always, 2 values A and B for it - The two values should have an extra price, like 100 for A and 150 for B - Create an attribute of type dynamic,…
**Steps to reproduce:** - Create an attribute of type always, 2 values A and B for it - The two values should have an extra price, like 100 for A and 150 for B - Create an attribute of type dynamic, 2 values C and D for it - C should have an extra price of 100 and 150 for D - Make a product with both of those product, set the price to 100 2 possibilities: - In the PoS, click the product, on the product popup, the price is 100 - This 100 is the product's price and does not change even if we change the values - Order that product and buy it with variants A and C - Click on the product again, the price is 300, which is correct - When we click on D, the price is reset to 100, but should be 350 **Why the fix:** When computing the popup's title, we try to get the current product based on the variants choices in the popup. If the product is found, we take that, because it means that it's already in the database. https://github.com/odoo/odoo/blob/0d7f5058664b501779b833609468e535b34356bf/addons/point_of_sale/static/src/app/components/popups/product_configurator_popup/product_configurator_popup.js#L260 If we do not find it, we just take the product template, which does not contain the current extra prices, which is why we got a price of 100 in the exemple. The product is not found because in the case of dynamic variants, the product is only created once it has been ordered at least once. Which means that for this newly created product, it is not yet in the database, so we take the product template instead of the product itself. We now also add the extra price for a product if it is undefined, meaning it has not been found in the database yet. We can't directly update the getter for the priceExtra, as it's also used to build the payload. As the rest of the code works fine with dynamic products with extra price the way it is sent now, we only change the title instead of changing the entire logic and computation. opw-6326125 Forward-Port-Of: odoo/odoo#273411
PR #247474 fixed an error where the lock date restriction was applied overzealously, restricting `stock.picking` models with a `scheduled_date` field before the lock date. This field does not affect accounting entries. The previous fix was to only check the `scheduled_date` field if the picking was in the `done` state. A more complete fix is to simply not check the `scheduled_date` field. opw-6311703 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-
Original PR description
PR #247474 fixed an error where the lock date restriction was applied overzealously, restricting `stock.picking` models with a `scheduled_date` field before the lock date. This field does not affect accounting entries. The previous fix was to only check the `scheduled_date` field if the picking was in the `done` state. A more complete fix is to simply not check the `scheduled_date` field. opw-6311703 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#270875
## Problem When generating accrual entries for multiple sale orders, the stock variation lines would all show the same order name, even if the line belonged to a different sale order. This is caused by the `order` variable being reused from a previous loop. ## Solution We will pull the order name directly from the order line in the current iteration. ## Steps to reproduce (Runbot v19) 1. Create a product with AVCO perpetual valuation 2. Make sure all accounts are configured properly (I
Original PR description
## Problem When generating accrual entries for multiple sale orders, the stock variation lines would all show the same order name, even if the line belonged to a different sale order. This is caused…
## Problem When generating accrual entries for multiple sale orders, the stock variation lines would all show the same order name, even if the line belonged to a different sale order. This is caused by the `order` variable being reused from a previous loop. ## Solution We will pull the order name directly from the order line in the current iteration. ## Steps to reproduce (Runbot v19) 1. Create a product with AVCO perpetual valuation 2. Make sure all accounts are configured properly (Income, Expense, Stock, and stock variation accounts) 3. Add units to the stock (it can be with an adjustment, as long as the product has a cost already set) 4. Create 2 separate sales orders for this product 5. Deliver both of the sales orders, do not invoice them 6. Now go to the Accounting App Review>Invoices to be issued 7. Select the 2 invoices that were created. The Revenue accrual lines are correct, with each SO being referenced, but on the Stock variation lines, only the last SO selected will appear. opw-6361032 Forward-Port-Of: odoo/odoo#277058
Calling the method in RPC causes an error: ``` TypeError: cannot marshal None unless allow_none is enabled ``` 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#277047 Forward-Port-Of: odoo/odoo#276541
Original PR description
Calling the method in RPC causes an error: ``` TypeError: cannot marshal None unless allow_none is enabled ``` 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#277047 Forward-Port-Of: odoo/odoo#276541
Miscellaneous changes
all_sm is referenced by two branches of the outer UNION, so PostgreSQL materializes it (a CTE used more than once is an optimization fence). Every query on report_stock_quantity therefore builds the forecast for all products/warehouses first and filters afterwards, so predicates like product_id can't reach the stock_move scan. This hurts single-product lookups such as _read_group() in mrp_report_bom_structure._get_stock_availability(), called repeatedly per component while rendering a BoM rep
Original PR description
all_sm is referenced by two branches of the outer UNION, so PostgreSQL materializes it (a CTE used more than once is an optimization fence). Every query on report_stock_quantity therefore builds the…
all_sm is referenced by two branches of the outer UNION, so PostgreSQL materializes it (a CTE used more than once is an optimization fence). Every query on report_stock_quantity therefore builds the forecast for all products/warehouses first and filters afterwards, so predicates like product_id can't reach the stock_move scan.
This hurts single-product lookups such as _read_group() in mrp_report_bom_structure._get_stock_availability(), called repeatedly per component while rendering a BoM report: each call does a full stock_move scan plus two sorts that spill to disk.
Marking all_sm NOT MATERIALIZED lets the planner inline it and push the product_id/warehouse_id filter down to an index scan, removing the full scan, the GENERATE_SERIES expansion and the on-disk sorts. warehouse_cte stays materialized (small and cheap).
Query generated from the _read_group:
```SQL
SELECT MIN("report_stock_quantity"."date")
FROM "report_stock_quantity"
WHERE (
(
(
(
("report_stock_quantity"."state" = 'forecast')
AND ("report_stock_quantity"."date" >= '2026-07-08')
)
AND ("report_stock_quantity"."product_id" = 15743)
)
AND ("report_stock_quantity"."product_qty" >= 1.0)
)
AND ("report_stock_quantity"."warehouse_id" = 4)
)
AND ("report_stock_quantity"."company_id" IN (1))
```
Before:
800 ms by _read_group in _get_stock_availability().
For opening a BoM overview with hundred of components takes 17 sec.
After:
25 ms by _read_group in _get_stock_availability().
Same BoM overview drops to 3 sec to open.
cc @Aurelienvd
I can send you EXPLAIN ANALYZE, but I prefer to not putting them here to avoid data leakage.
Forward-Port-Of: odoo/odoo#277235
Forward-Port-Of: odoo/odoo#2750228 changes
Enhancements to existing features
This commit adds `company_register` VAT Registry (VAT ID) to the invoice header for [legal reasons](https://lex.uz/ru/docs/4948595#5225819). Also, the condition for `TIN` has been updated to be 14 digits if the contact is a person and 9 digits if it is a company. Upgrade PR: https://github.com/odoo/upgrade/pull/10679 task-6205255
Original PR description
This commit adds `company_register` VAT Registry (VAT ID) to the invoice header for [legal reasons](https://lex.uz/ru/docs/4948595#5225819). Also, the condition for `TIN` has been updated to be 14 digits if the contact is a person and 9 digits if it is a company. Upgrade PR: https://github.com/odoo/upgrade/pull/10679 task-6205255
Resolved issues and error corrections
### Description of the issue/feature this PR addresses: - Opening Studio on a form containing a `Many2many` field using the `many2many_tags_email` widget crashes with an OWL prop validation error. - **Steps to reproduce:** 1. Open any form view (e.g., Contacts) and enter `Studio`. 2. Create a new `Many2many` custom field on a model such as `res.partner` . 3. Set the field's widget to `many2many_tags_email` and save the customization. 4. Exit Studio and populate the field with one or
Original PR description
### Description of the issue/feature this PR addresses: - Opening Studio on a form containing a `Many2many` field using the `many2many_tags_email` widget crashes with an OWL prop validation error. -…
### Description of the issue/feature this PR addresses: - Opening Studio on a form containing a `Many2many` field using the `many2many_tags_email` widget crashes with an OWL prop validation error. - **Steps to reproduce:** 1. Open any form view (e.g., Contacts) and enter `Studio`. 2. Create a new `Many2many` custom field on a model such as `res.partner` . 3. Set the field's widget to `many2many_tags_email` and save the customization. 4. Exit Studio and populate the field with one or more related records. 5. Open Studio again on the same form view. This results in the following error: ```.js Error: Invalid props for component 'RecipientTag': 'onDelete' is undefined (should be a value) ``` ### Current behavior before PR: - When opening Studio on a form containing a `Many2many` field with the `many2many_tags_email` widget, the field is rendered with `onDelete` set to undefined by `Many2ManyTagsField`. Starting from `saas-19.1`, the `many2many_tags_email` widget uses the new [RecipientTag](https://github.com/odoo/odoo/blob/saas-19.1/addons/mail/static/src/core/web/recipient_tag.js) component, which requires onDelete to be defined. As a result, Owl's prop validation fails when RecipientTag receives `onDelete = undefined`, causing Studio to crash with an Invalid props for component 'RecipientTag' error. ### Desired behavior after PR is merged: - `RecipientTag` should allow `onDelete` to be optional so that it can also be used when the parent field does not provide a delete callback. This prevents the Owl prop validation error when opening Studio, while keeping the existing delete functionality unchanged for editable fields where onDelete is available. opw:6395209 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
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 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#275000# Step to reproduce - Install eCommerce - Activate dev mode with tests assets (important!) - Go to the website & add a Countdow in the footer - Add a new product from the website system tray - Put any name & Save - Go into Edit mode - In the Style tab, (un)toggle "Tax Indication" (may need to do it multiple times) > Note that the issue is quite inconsistent to reproduce # Issue A traceback is shown # Cause The only thing I'm sure of is that the error is caused by this code : htt
Original PR description
# Step to reproduce - Install eCommerce - Activate dev mode with tests assets (important!) - Go to the website & add a Countdow in the footer - Add a new product from the website system tray - Put…
# Step to reproduce - Install eCommerce - Activate dev mode with tests assets (important!) - Go to the website & add a Countdow in the footer - Add a new product from the website system tray - Put any name & Save - Go into Edit mode - In the Style tab, (un)toggle "Tax Indication" (may need to do it multiple times) > Note that the issue is quite inconsistent to reproduce # Issue A traceback is shown # Cause The only thing I'm sure of is that the error is caused by this code : https://github.com/odoo/odoo/blob/8759429547e42e9f63b15a7c80475be46ef437e2/addons/website/static/tests/tour_utils/lifecycle_dep_interaction.js#L18-L20 And that it is linked to `browser.localStorage`. I suspect it is due to some weird localStorage and WysiwygAdapter interaction : https://github.com/odoo/odoo/blob/d6a08b67a948f569a1ca893b6337ce50b4ef9f07/addons/website/static/tests/tours/widget_lifecycle.js#L53-L60 But I can't be sure because debugging tools do not seem to be working. See the inverstigation comment in the associated PR for more information. # Proposed Solution Since this code is only used for this test : https://github.com/odoo/odoo/blob/96a0a9a0332ae460973b6f01b461a0f7e3e2f7fa/addons/website/static/tests/tours/interaction_lifecycle.js#L14-L15 And the test directly parses from the `window.localStorage` : https://github.com/odoo/odoo/blob/96a0a9a0332ae460973b6f01b461a0f7e3e2f7fa/addons/website/static/tests/tours/interaction_lifecycle.js#L50 We can use `window.localStorage` instead of `browser.localStorage` as it fixes the issue opw-6246850 Forward-Port-Of: odoo/odoo#272736
## Problem When generating accrual entries for multiple sale orders, the stock variation lines would all show the same order name, even if the line belonged to a different sale order. This is caused by the `order` variable being reused from a previous loop. ## Solution We will pull the order name directly from the order line in the current iteration. ## Steps to reproduce (Runbot v19) 1. Create a product with AVCO perpetual valuation 2. Make sure all accounts are configured properly (I
Original PR description
## Problem When generating accrual entries for multiple sale orders, the stock variation lines would all show the same order name, even if the line belonged to a different sale order. This is caused…
## Problem When generating accrual entries for multiple sale orders, the stock variation lines would all show the same order name, even if the line belonged to a different sale order. This is caused by the `order` variable being reused from a previous loop. ## Solution We will pull the order name directly from the order line in the current iteration. ## Steps to reproduce (Runbot v19) 1. Create a product with AVCO perpetual valuation 2. Make sure all accounts are configured properly (Income, Expense, Stock, and stock variation accounts) 3. Add units to the stock (it can be with an adjustment, as long as the product has a cost already set) 4. Create 2 separate sales orders for this product 5. Deliver both of the sales orders, do not invoice them 6. Now go to the Accounting App Review>Invoices to be issued 7. Select the 2 invoices that were created. The Revenue accrual lines are correct, with each SO being referenced, but on the Stock variation lines, only the last SO selected will appear. opw-6361032 Forward-Port-Of: odoo/odoo#277058
Calling the method in RPC causes an error: ``` TypeError: cannot marshal None unless allow_none is enabled ``` 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#277047 Forward-Port-Of: odoo/odoo#276541
Original PR description
Calling the method in RPC causes an error: ``` TypeError: cannot marshal None unless allow_none is enabled ``` 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#277047 Forward-Port-Of: odoo/odoo#276541
Problem: Changing the text alignment of a table header in Studio reports has no effect. Cause: When the alignment is already defined by a CSS class using `!important` (for example, `text-center`), the inline style applied from the toolbar is ignored. Solution: Backport commit 373be20905bcb11f8323a986053e3dc7996ce567. Steps to reproduce: - Open the invoice report. - Change the alignment of a table header. - Observe that the new alignment is not applied. opw-6389158 --- I con
Original PR description
Problem: Changing the text alignment of a table header in Studio reports has no effect. Cause: When the alignment is already defined by a CSS class using `!important` (for example, `text-center`), the inline style applied from the toolbar is ignored. Solution: Backport commit 373be20905bcb11f8323a986053e3dc7996ce567. Steps to reproduce: - Open the invoice report. - Change the alignment of a table header. - Observe that the new alignment is not applied. opw-6389158 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276470
Note: In odoo all date/datetime fields are stored and computed by default as UTC Before this commit, dates were called using local timezone getters. This caused the time returned from web to be shifted by the timezone as the dates returned would be treated as UTC. After this commit, dates are now called using UTC timzone getters. Now all web times are retrived as UTC and in sync with the rest of the odoo fields and computations. task-6271421 Forward-Port-Of: odoo/odoo#276683 Forward-Po
Original PR description
Note: In odoo all date/datetime fields are stored and computed by default as UTC Before this commit, dates were called using local timezone getters. This caused the time returned from web to be shifted by the timezone as the dates returned would be treated as UTC. After this commit, dates are now called using UTC timzone getters. Now all web times are retrived as UTC and in sync with the rest of the odoo fields and computations. task-6271421 Forward-Port-Of: odoo/odoo#276683 Forward-Port-Of: odoo/odoo#265250
6 changes
Resolved issues and error corrections
## Steps to Reproduce: _(cryptography version > 43.0.0)_ 1. Install the `l10n_sa_edi` module. 2. Switch to SA Company. 3. Set the company name to an Arabic string between 32 and 64 characters. (e.g; `مجموعة النخبة العالمية للاستشارات الفنية`) 5. Accounting > Configuration > Journals. 6. Open a Sales type journal. 7. Click "Re-onboard" in the ZATCA tab. 8. Enter an OTP and click "Request". ## Error: `ValueError: Attribute's length must be >= 1 and <= 64, but it was 98` ## Caus
Original PR description
## Steps to Reproduce: _(cryptography version > 43.0.0)_ 1. Install the `l10n_sa_edi` module. 2. Switch to SA Company. 3. Set the company name to an Arabic string between 32 and 64 characters. (e.g;…
## Steps to Reproduce: _(cryptography version > 43.0.0)_
1. Install the `l10n_sa_edi` module.
2. Switch to SA Company.
3. Set the company name to an Arabic string between 32 and 64 characters.
(e.g; `مجموعة النخبة العالمية للاستشارات الفنية`)
5. Accounting > Configuration > Journals.
6. Open a Sales type journal.
7. Click "Re-onboard" in the ZATCA tab.
8. Enter an OTP and click "Request".
## Error:
`ValueError: Attribute's length must be >= 1 and <= 64, but it was 98`
## Cause:
The CSR validation checks the length of characters, if combined common_name (or other fields) are less than 64 characters, it passes the condition. - [1] But the cryptography library validates UTF-8 byte length for string values. Arabic characters take 2 bytes in UTF-8, causing the byte length to exceed the 64-byte limit enforced by the cryptography.
**Note:**
Starting with cryptography version 43.0.0, the library enforces the UTF-8 byte length limit for CSR string values during certificate creation. (Ref: https://github.com/pyca/cryptography/pull/11201)
## Fix:
Validate the UTF-8 encoded byte length instead of the character length.
[1] - https://github.com/odoo/odoo/blob/a66fedcaf555660e484a2becc49a9b7e602f5924/addons/l10n_sa_edi/models/certificate.py#L92
sentry-7608376856
Forward-Port-Of: odoo/odoo#276861Stripe recommends connecting to a reader returned by the most recent discovery call. However, the POS Stripe interface discovered readers as soon as the Stripe Terminal object was created, during POS loading. This means a POS reload performed long before the first payment could populate `pos.discoveredReaders` with stale reader objects. If the first Stripe Terminal payment happens much later, the SDK may try to connect using outdated reader/credential state and fail with an expired Connection
Original PR description
Stripe recommends connecting to a reader returned by the most recent discovery call. However, the POS Stripe interface discovered readers as soon as the Stripe Terminal object was created, during POS loading. This means a POS reload performed long before the first payment could populate `pos.discoveredReaders` with stale reader objects. If the first Stripe Terminal payment happens much later, the SDK may try to connect using outdated reader/credential state and fail with an expired ConnectionToken. Move reader discovery to `connectReader()` so Odoo connects using fresh discovery results, and stop discovering readers eagerly when creating the Stripe Terminal instance. opw-6311626 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276875
e39bf6c6ab31e57d472a552cb9b902496e6323ae introduced a blacklist to email sending, to filter out "alias emails" (catchall...) & the root partner email (odoobot) from being sent certain emails, such as mailings. By default, odoobot email is odoobot@example.com. However, there are cases where users will have a legitimate partner that matches the odoobot email; an example of this is saas config, which automatically changes the odoobot email to the admin email set on database spin-up. This
Original PR description
e39bf6c6ab31e57d472a552cb9b902496e6323ae introduced a blacklist to email sending, to filter out "alias emails" (catchall...) & the root partner email (odoobot) from being sent certain emails, such as mailings. By default, odoobot email is odoobot@example.com. However, there are cases where users will have a legitimate partner that matches the odoobot email; an example of this is saas config, which automatically changes the odoobot email to the admin email set on database spin-up. This prevents the database admin from receiving their own mailings. To fix this, the root partner email is now only added to the blacklist if no active partner has the same email. Steps to reproduce: - Add a mailing contact with the same email as the root partner - Send a mailing to that mailing contact task-4893615
Before this commit, decreasing the quantity of a move whose move lines are expressed in another unit of measure removed the wrong quantity from the lines, because the two conversions between the move unit and the line unit converted a value to its own unit, hence did nothing. Steps to reproduce: - create a product in Units with available stock - create a delivery for 2 Dozen of it and mark it as todo - in the detailed operations, change the unit of the move line to Units (24) - lower the
Original PR description
Before this commit, decreasing the quantity of a move whose move lines are expressed in another unit of measure removed the wrong quantity from the lines, because the two conversions between the move…
Before this commit, decreasing the quantity of a move whose move lines are expressed in another unit of measure removed the wrong quantity from the lines, because the two conversions between the move unit and the line unit converted a value to its own unit, hence did nothing. Steps to reproduce: - create a product in Units with available stock - create a delivery for 2 Dozen of it and mark it as todo - in the detailed operations, change the unit of the move line to Units (24) - lower the move quantity from 2 to 1 Dozen The move line ends up with 23 Units instead of 12: the decrease of 1 Dozen is applied as 1 Unit on the line and considered fully processed. The remaining 11 units stay reserved and counted on the transfer. Convert the remaining decrease from the move unit to the line unit when taking it from a line, and the taken quantity back to the move unit when updating the remaining decrease. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276774
iOS devices currently display the first letter of the website name instead of a favicon when creating a shortcut. This commit adds the `apple-touch-icon` link tag referencing the favicon to ensure the icon displays correctly. This commit is a backport of [1], which was merged in master(saas-19.2). task-5427275 [1]: https://github.com/odoo/odoo/commit/2506fdfc49f1515aea7e715e9f6d66418a093401 Forward-Port-Of: odoo/odoo#277723
Original PR description
iOS devices currently display the first letter of the website name instead of a favicon when creating a shortcut. This commit adds the `apple-touch-icon` link tag referencing the favicon to ensure the icon displays correctly. This commit is a backport of [1], which was merged in master(saas-19.2). task-5427275 [1]: https://github.com/odoo/odoo/commit/2506fdfc49f1515aea7e715e9f6d66418a093401 Forward-Port-Of: odoo/odoo#277723
When installing the module document_account_peppol, the user has the choice to import his Peppol invoices into the Documents app directly, but also to block the import in Accounting, by removing the Peppol import journal. In that last case, the Peppol application response flow is broken, the document model does not contain the necessary information to handle responses as the imported invoices do. (In stable) We took the decision to remove the ApplicationResponse service from users that bl
Original PR description
When installing the module document_account_peppol, the user has the choice to import his Peppol invoices into the Documents app directly, but also to block the import in Accounting, by removing the Peppol import journal. In that last case, the Peppol application response flow is broken, the document model does not contain the necessary information to handle responses as the imported invoices do. (In stable) We took the decision to remove the ApplicationResponse service from users that block the invoice import flow by removing the import journal. For PDP, the responses are required, but as the block is completely replaced in the view, and reuses the basic account_peppol condition for the required attribute, the account peppol purchase journal will always be required if the company is registered on Peppol/PDP. Nothing to do in 18.0. task-6191644 Forward-Port-Of: odoo/odoo#270091
22 changes
Enhancements to existing features
Users can again export dynamic folder views from Documents into spreadsheets and Knowledge link settings, making it easier to reuse up-to-date document views. The change also protects folder access tokens from being exposed through Knowledge view settings.
Original PR description
It is convenient to export a dynamic view of a folder in both spreadsheet and knowledge links settings. Care is taken to avoid leaking access folders tokens through the search panel/model's state in knowledge. Task-5180137
The quick product creation window in the website editor has been redesigned so product details and images are easier to manage. When editing a product image, users are now taken directly to the media manager, making the process smoother and less cramped.
Original PR description
In the website editor, it is possible to quickly add a new product. However, the opened view looks bad, especially when adding an image, as everything is squeezed. This commit improves the UI and opens the media manager when editing the image. Community: https://github.com/odoo/odoo/pull/278040 task-6307166
Loans can now include analytic accounts so loan-related journal entries reflect the correct analytic distribution. This helps businesses track loan costs and allocations more accurately in their reporting.
Original PR description
Similar to assets, users need the ability to add analytic accounts to loans so that the analytic distribution impacts the generated journal entries. Task-4575979
POS operators can now see self-order counts in the same notification area as other order status updates, making it easier to monitor incoming activity. The update also adds an option to temporarily snooze the self-order service for a chosen period, giving staff more control during busy or unavailable times.
Original PR description
In this commit: ------------------ - Unified the order status notification widget to display self-order counts within the same widget. - Implemented a toggle to snooze the self-order service for a specified duration. task: 6110229 Community PR: https://github.com/odoo/odoo/pull/261677 Upgrade PR: https://github.com/odoo/upgrade/pull/10064
The Knowledge app now handles popover context automatically instead of passing it manually in comment and sidebar components. This simplifies the underlying implementation and should make future maintenance safer without changing the user experience.
Original PR description
This commit removes the env given to usePopover. usePopover and useOwnedDialogs now get the current owl scope by themselves (with an option) and propagates it to the popover.
Odoo Box device records now include a connection type, making it easier for users to match each record with the corresponding physical device. This improves day-to-day identification and support for connected devices.
Original PR description
We added a connection type to help users find which record corresponds to which actual device. see odoo/obox#203 task-6332387
Users can now enable or disable each AI provider independently of whether an API key is saved. This makes AI configuration easier to manage and improves feedback when API keys are missing or invalid.
Original PR description
Prior to this PR, user had to delete the API key set in order to disable the corresponding provider option in the AI config view. With this PR, we removed the compute method to allow the enable/disable provider option independently from the API key value. Additionally, reworded error messages when API keys are unable and added custom messages when provided API key is invalid. task: 6331248
Resolved issues and error corrections
Spanish VAT book exports now ignore negative tax components when calculating displayed tax amounts. This prevents valid EU vendor bill taxes from incorrectly appearing as zero, improving accuracy in tax reporting.
Original PR description
Problem: In the Spanish VAT books, taxes with negative component (like 21% EU G) always show their amounts as zero. Steps to reproduce: 1. Install the l10n_es_reports module and select the Spanish company 2. Create a vendor bill with a vendor from another EU country and add a product 3. Make sure the tax applied to the product has a negative component (like 21% EU G) 4. Confirm the bill 5. Go to Accounting > Reporting > Tax Return 6. Generate the VAT books from the action menu and check the tax amounts 7. Notice how the tax amount is zero, even though the tax was applied to the bill Cause: When calculating the tax amounts, the negative component cancels out the positive component, leading to the amount always showing as zero in the VAT books. opw-6169766 Forward-Port-Of: odoo/enterprise#124030 Forward-Port-Of: odoo/enterprise#123738
The timesheet assistant now recognizes events from coding editors correctly, so they display with the intended development icon. This makes assistant activity clearer for users who track work connected to development tools.
Original PR description
In the assistant, events from a coding editor use the "code" event type, which doesn't exist. This PR changes it to the correct value, which is "development". Task-6392585 Forward-Port-Of: odoo/enterprise#124502
Belgian payroll now correctly treats employees with a judicially separated marital status when calculating withholding tax and special social security contributions. This prevents affected payslips from applying zero rates or excessive reductions, improving payroll accuracy and compliance.
Original PR description
**Steps to Reproduce:** 1. Create a new employee. 2. Set their marital status to "Judicially Separated". 3. Generate a payslip. **Reason:** - The "Judicially Separated" marital status was not explicitly included in the conditions for calculating withholding taxes or special social contributions. As a result, employees with this status bypassed the calculations entirely, receiving a rate of 0 for both and a significantly larger reduction on master which also appears to be incorrect. **Solution:** - Included the 'separated' status in isolated tax and CSSS logic. Task-6321245 Forward-Port-Of: odoo/enterprise#124992 Forward-Port-Of: odoo/enterprise#121457
The barcode app now applies a default limit when loading reusable packages for transfers. This prevents very large package lists from causing long waits, improving responsiveness for warehouses with tens of thousands of packages.
Original PR description
# How to reproduce - Have a lot of reusable & locationless packages (e.g. > 10 000) - Go to any transfer via the barcode application # The issue There is a very long loading time, even in local…
# How to reproduce - Have a lot of reusable & locationless packages (e.g. > 10 000) - Go to any transfer via the barcode application # The issue There is a very long loading time, even in local testing. The client of the tickets experiences loadings up to 120 seconds with 50k packages # Cause When opening a transfer, we load barcode data by doing an API call to `_get_stock_barcode_data` : https://github.com/odoo/enterprise/blob/fe058ef501767b7ed9758fc9264f664b32c6bae8/stock_barcode/models/stock_picking.py#L85 During this we preload a lot of records, notably packages : https://github.com/odoo/enterprise/blob/fe058ef501767b7ed9758fc9264f664b32c6bae8/stock_barcode/models/stock_picking.py#L128 The issue is that in the fields we read for the packages, two of them (`location_dest_id` & `contained_quant_ids`) have a `_read_group` in their compute (or in the compute of one of the fields they depend on) : https://github.com/odoo/odoo/blob/625e6bcbd66c45ea2f699df14e2ea12e2e28a893/addons/stock/models/stock_package.py#L65 https://github.com/odoo/odoo/blob/625e6bcbd66c45ea2f699df14e2ea12e2e28a893/addons/stock/models/stock_package.py#L146 Fortunately, this does not mean that we make a query for every records. Instead, in Odoo, we fetch records in batch of 1000. So, for the case of the client, every time he loads the database, the backend does 50 000 / 1000 x 2 = 100 queries, which hinders performance a lot A [PERF] commit was done to limit the number of packages that are fetched base on a config parameter. The problem is that this parameter does not have a default value, so clients still end up with the problem. [PERF]: https://github.com/odoo/enterprise/commit/efe18bc1ea479270e42846986d7ed449b0865617 # Proposed Solution Add a default value for that config parameter. The exact value is up to discussion opw-6200730 Forward-Port-Of: odoo/enterprise#124538 Forward-Port-Of: odoo/enterprise#123696
The AI module’s automated tests were adjusted to focus only on editable email content after a related editor behavior change. This helps keep quality checks reliable without changing what end users see or do.
Original PR description
This commit updates the tests after https://github.com/odoo/odoo/pull/276332 to query only the editable content, ignoring the DOM clone created by `convert_inline`. opw-3776054 Forward-Port-Of: odoo/enterprise#124648
Envia shipping label requests now send the weight of each item when using Amazon shipping. This prevents Amazon from applying default weights that could incorrectly block shipments with larger quantities.
Original PR description
**Issue:** Envia API documentation is very bad. When trying to generate an Amazon Ground shipping with Envia, the API will sometimes reject the payload with the following error: `Total items weight…
**Issue:** Envia API documentation is very bad. When trying to generate an Amazon Ground shipping with Envia, the API will sometimes reject the payload with the following error: `Total items weight exceeds package weight. Please refer to API documentation for allowable limits. (D-703)` Even though the [Envia documentation](https://docs.envia.com/reference/create-shipping-label) doesn't include it, it seems that Amazon requires the weight for each product. If the payload doesn't include the per-item weight, Amazon will set a default weight, which will cause the error to show up if the delivery contains a high quantity. This can be a blocking issue for some customers. **Steps to reproduce on a fresh DB:** - Install Inventory, Sales, and Envia Shipping - Switch company to be based in India (need to provide an address to deliver from, I just used the Odoo India address - InfoCity Gate, Gandhinagar, Gujarat 382007) - Configure an Amazon delivery carrier with Envia (India seems to be the only country that supports Amazon with Envia) - Inventory > Configuration > Delivery Methods > Envia.com method - Must be in a Production environment (because Envia's sandbox server does not work for some reason?) - Add an Envia Production Access Token (will have to use one with some funds) - Change 'Ship From' to India - Configure the `Envia.com Service Name`, set Carrier and Service to AMAZON and AMAZON - Amazon Shipping Standard - Create a demo product, give it an arbitrary weight like 0.1 kg - Create a sales order to an Indian customer, include the demo product with a high quantity (like 20), confirm (might have to create a warehouse and configure the customer's information) - On the generated picking, set the Carrier to Envia.com on the Additional Info tab - When trying to Validate, it should throw the error **Fix:** When generating the payload in _get_shipping_lines() in envia_request, include the item weight in the dictionary. Related ticket: opw-6261682 Forward-Port-Of: odoo/enterprise#125017 Forward-Port-Of: odoo/enterprise#123935
Merging manufacturing orders now removes pending quality checks from the cancelled source orders. This prevents outdated quality tasks and buttons from remaining visible, reducing confusion for manufacturing and quality teams.
Original PR description
Version: -------- - 18.0+ Steps to reproduce: ------------------- - Install `quality_mrp` - Create a manufactured product with a BoM - Create a Quality Point for the `Manufacturing` operation of that…
Version: -------- - 18.0+ Steps to reproduce: ------------------- - Install `quality_mrp` - Create a manufactured product with a BoM - Create a Quality Point for the `Manufacturing` operation of that product - Create and confirm multiple Manufacturing Orders - Verify that each MO generates a quality check - From the MO list view, select the MOs and merge them from the gear menu(merge) Issue: ------ When Manufacturing Orders are merged, All MOs are cancelled but it keep their quality checks in the 'To Do' state. As a result: - The quality checks remain linked to cancelled MOs - The 'Quality Checks' smart button is still displayed on cancelled MOs Expected behavior: ------------------ - Pending quality checks should be deleted when the MO is cancelled - The 'Quality Checks' smart button should no longer be displayed Cause: ------ A previous [fix](https://github.com/odoo-dev/enterprise/commit/db93bd2ee313b6bb1959a41c9beb9850975b9959 ) introduced logic to remove pending quality checks when a Manufacturing Order is cancelled: This logic was implemented in `action_cancel()` by unlinking quality checks associated with the cancelled MO: https://github.com/odoo/enterprise/blob/20bc0eb5c2cec67eecd3b44450934e23370b48f2/quality_mrp/models/mrp_production.py#L94-L97 However, when MOs are merged, the merge flow does not call `action_cancel()`. Instead, it directly invokes `_action_cancel()` on the source Manufacturing Orders: https://github.com/odoo/odoo/blob/aca0b7289c68fc7a75d47ab313f5f791ebf30f7d/addons/mrp/models/mrp_production.py#L1778 Since the quality check cleanup is implemented only in `action_cancel()`, it is bypassed during the merge process. As a result, the source MOs are cancelled but their pending quality checks remain in place. --- Related community PR : https://github.com/odoo/odoo/pull/267987 --- opw-6260735
This fix ensures Starshipit delivery item details send the product barcode as the barcode and the internal reference as the SKU. This helps avoid confusion in shipping records and improves accuracy when matching delivered items.
Original PR description
Current behavior: --- Barcode is assigned to sku in the item model payload Fix: --- Assigned product barcode in barcode and internal reference in sku opw-6221412
The website AI now receives clearer guidance when creating or changing buttons, so visual edits such as text color are applied correctly and no longer get undone by page cleanup rules. Video additions are also handled more consistently by removing an unintended faded appearance.
Original PR description
Steps to see the issue: - start editing a page - ask AI to add a button - ask AI to change the text color of the dropped button => AI reports the change as applied, but the frontend rolls it back during normalization because the button keeps the `btn-primary` class, whose style takes precedence over inline color. To fix this, we add explicit instructions for button edits so AI uses `btn-custom` and defines complete button styling when changing button appearance. We also move video-related prompt into the same snippet specific instructions section for consistency and easier maintenance. task-6196298
This fixes an issue where contact details in the VoIP transfer screen would close automatically during an active call. Users can now keep a contact entry open while deciding where to transfer the call, avoiding interruption and confusion.
Original PR description
Commit [1] tried to make it so some VoIP UI state resets when it should: - Resetting the scroll to the top of search results - Closing opened tab entries This introduced this bug: - Start a call -…
Commit [1] tried to make it so some VoIP UI state resets when it should: - Resetting the scroll to the top of search results - Closing opened tab entries This introduced this bug: - Start a call - Click the transfer button - Click on a contact tab entry to open it => Bug: after max 1 second it closes. It closes in fact on any re-render... and one happens because of the in-call timer update, every second. Why does it happen on any re-render although it is implemented thanks to a `useEffect` that normally only subscribes to its inner reactive parts? Because calling `this.props.onListContextChange();` actually subscribes to `this.props.onListContextChange` changes... and it changes every re-render because it is assigned an arrow function in the component XML. This might be considered an Owl bug later... same as arrow functions are considered the same for re-renders (.alike), they could be considered as such for `useEffect` triggers? This commit meanwhile fixes the bug by removing that `onListContextChange` props: it was given the same value everywhere, let's just inline that for now. [1]: https://github.com/odoo/enterprise/commit/690be9aefc8e60f43a26cf5cadede842baed7fd6
This fix aligns manufacturing work order timelines with updated planning behavior. It also adjusts duration calculations in grouped Gantt views so users see more accurate scheduling information.
Original PR description
[This PR](https://github.com/odoo/odoo/pull/106990) modifies the behavior of the planned dates of workorder so some tests must be adapted as well as the values used to compute the duration of the aggregated grouped pills of `MRPWorkorderGanttRow` opw-3008089
This fix prevents database upgrades from failing when an HR document folder was previously deleted or disabled. The system now skips unavailable employee folders when adding the HR signing shortcut, keeping upgrades running smoothly without restoring unwanted folders.
Original PR description
Steps to reproduce: 1 Install documents_hr and hr_sign on saas-19.1. 2 Go to Settings → Documents → disable Human Resources. 3 Open the Documents app and delete the Employees - My Company folder. 4…
Steps to reproduce:
1 Install documents_hr and hr_sign on saas-19.1.
2 Go to Settings → Documents → disable Human Resources.
3 Open the Documents app and delete the Employees - My Company folder.
4 Upgrade the database to saas-19.2.
Issue:
- During the upgrade, the post-init hook attempts to embed the HR Sign action into predefined document folders. Since the Employees - My Company folder has been deleted (or is inactive), the folder lookup returns no record, leading to the following error:
```python3
Traceback (most recent call last):
File "/home/odoo/src/odoo/saas-19.2/odoo/service/server.py", line 1664, in preload_registries
registry = Registry.new(dbname, update_module=update_module, install_modules=config['init'], upgrade_modules=config['update'], reinit_modules=config['reinit'])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/saas-19.2/odoo/tools/func.py", line 65, in locked
return func(inst, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/saas-19.2/odoo/orm/registry.py", line 186, in new
load_modules(
File "/home/odoo/src/odoo/saas-19.2/odoo/modules/loading.py", line 465, in load_modules
load_module_graph(
File "/home/odoo/src/odoo/saas-19.2/odoo/modules/loading.py", line 244, in load_module_graph
getattr(py_module, post_init)(env)
File "/home/odoo/src/enterprise/saas-19.2/documents_hr_sign/__init__.py", line 12, in _embed_sign_post_init
folders.with_user(SUPERUSER_ID)._embed_action(sign_action.id)
File "/home/odoo/src/enterprise/saas-19.2/documents/models/documents_document.py", line 1643, in _embed_action
folder.action_folder_embed_action(folder.id, action_id)
File "/home/odoo/src/enterprise/saas-19.2/documents/models/documents_document.py", line 1614, in action_folder_embed_action
return self.get_documents_actions(folder_id)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/enterprise/saas-19.2/documents/models/documents_document.py", line 1522, in get_documents_actions
raise UserError(_('This folder does not exist or is not accessible.'))
odoo.exceptions.UserError: Esta carpeta no existe o no es accesible.
```
Root cause:
- As part of documents_sign, the documents_hr_sign action is embedded into predefined document folders (introduced in https://github.com/odoo/enterprise/pull/101890).
- The folder lookup relies on [_search()](https://github.com/odoo/odoo/blob/85992d5f5f8caeacdcc570fb9fefb4cfcec6460c/odoo/orm/models.py#L4681-L4691), which filters out inactive records
through the active test. Consequently, [search_fetch()](https://github.com/odoo/odoo/blob/85992d5f5f8caeacdcc570fb9fefb4cfcec6460c/odoo/orm/models.py#L1441-L1451) returns no matching
folder when the predefined folder has been deleted or deactivated. It will
try to get document actions of predefined folder here, so if the folder is
https://github.com/odoo/enterprise/blob/6d334a17d10faec33d60f4a8d7d263c091bb456e/documents/models/documents_document.py#L1592
inactive it will not be able to read the folder here.
https://github.com/odoo/enterprise/blob/6d334a17d10faec33d60f4a8d7d263c091bb456e/documents/models/documents_document.py#L1494
Fix:
- Instead of attempting to embed the Sign action into all company employee folders, filter out inactive folders before calling _embed_action().
- This ensures the post-init hook only processes active employee document folders. If a predefined folder has been deleted or deactivated, it is skipped preventing the upgrade from attempting to embed an action into an inaccessible folder and avoiding the resulting UserError.
opw-6358063
upg-4449902
Forward-Port-Of: odoo/enterprise#123846Code cleanup and technical improvements
This update keeps Odoo Studio's form editor aligned with recent interface changes in the underlying Odoo platform. It helps ensure Studio continues to target the correct form sections when users customize screens, with no expected visible change for everyday users.
Original PR description
With OWL3 refactoring of notebook component in odoo/odoo#269101 we adapt the xpaths Community PR: https://github.com/odoo/odoo/pull/269101
The Knowledge app now passes comment thread sizing information more directly between components. This is an internal cleanup that helps keep the comments feature easier to maintain without changing how users interact with it.
Original PR description
This commit removes a `useSubEnv` in comments handler that provided thread heights. The child component still needs these heights. They are given in props instead.
Several Odoo Enterprise apps now use a newer internal method for handling user interface events. This keeps the affected areas aligned with current platform practices and helps maintain reliability without changing visible functionality.
Original PR description
\* iap_extract,knowledge,spreadsheet_edition,voip This commit replaces all occurence of `useExternalListener` by `useListener`.
12 changes
Resolved issues and error corrections
#### Description of the issue/feature this PR addresses: On Thai-language documents, `res.currency.amount_to_text` (used e.g. for `account.move.amount_total_words` on invoice reports) renders amounts with satang as "หนึ่งร้อยห้าสิบ Baht และ ยี่สิบห้า Satang". Thai financial wording never uses the conjunction "และ" ("and") between the Baht and Satang parts — the standard format (cheques, tax invoices, Excel's BAHTTEXT) is "หนึ่งร้อยห้าสิบบาทยี่สิบห้าสตางค์". Confirmed by an Odoo translator on op
Original PR description
#### Description of the issue/feature this PR addresses: On Thai-language documents, `res.currency.amount_to_text` (used e.g. for `account.move.amount_total_words` on invoice reports) renders amounts…
#### Description of the issue/feature this PR addresses:
On Thai-language documents, `res.currency.amount_to_text` (used e.g. for `account.move.amount_total_words` on invoice reports) renders amounts with satang as "หนึ่งร้อยห้าสิบ Baht และ ยี่สิบห้า Satang". Thai financial wording never uses the conjunction "และ" ("and") between the Baht and Satang parts — the standard format (cheques, tax invoices, Excel's BAHTTEXT) is "หนึ่งร้อยห้าสิบบาทยี่สิบห้าสตางค์". Confirmed by an Odoo translator on opw-6347437.
#### Current behavior before PR:
The Thai translation of the amount_to_text template keeps the English conjunction as "และ", producing incorrect Thai monetary wording such as "หนึ่งร้อยห้าสิบ Baht และ ยี่สิบห้า Satang".
#### Desired behavior after PR is merged:
The Thai msgstr no longer contains " และ ", so 150.25 THB renders as "หนึ่งร้อยห้าสิบ Baht ยี่สิบห้า Satang" (with native labels: "หนึ่งร้อยห้าสิบบาทยี่สิบห้าสตางค์"). The source term and all other languages are unchanged. Includes a regression test asserting Thai output has no "และ" and that English output keeps "and".
opw-6347437
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prBefore this commit, when adding a line without a product to an invoice or credit note, `_get_most_frequent_account_for_partner` picked the partner's most-used account, filtered to an income or expense account depending on `get_inbound_types` and `get_outbound_types`. Those helpers classify move types by cash-flow direction which is correct for choosing a receivable and payable account but wrong for choosing an income ro expense account: they group `in_refund` with `out_invoice` as "inbound",
Original PR description
Before this commit, when adding a line without a product to an invoice or credit note, `_get_most_frequent_account_for_partner` picked the partner's most-used account, filtered to an income or…
Before this commit, when adding a line without a product to an invoice or credit note, `_get_most_frequent_account_for_partner` picked the partner's most-used account, filtered to an income or expense account depending on `get_inbound_types` and `get_outbound_types`. Those helpers classify move types by cash-flow direction which is correct for choosing a receivable and payable account but wrong for choosing an income ro expense account: they group `in_refund` with `out_invoice` as "inbound", and `out_refund` with `in_invoice` as "outbound". As a result, a Vendor Credit Note line with no product would be filtered to income accounts instead of expense accounts, and a Customer Credit Note line to expense accounts instead of income accounts. This only surfaced for contacts who are both customer and vendor, since the query needs matching history to return a result; otherwise it silently falls back to the journal's default account, masking the bug for ordinary contacts. This commit uses `get_sale_types` and `get_purchase_types` instead, which classify by document side, sale vs. purchase rather than cash-flow direction, matching the classification already used for product-based lines `is_sale_document` and `is_purchase_document` opw-6373124 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276846
…oves Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
…oves 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
**Issue** A credit note created before returning any stock may compute an incorrect COGS value. **Steps to reproduce** - Create a product valued with AVCO and a standard price of 10 - Create and confirm a SO for 2 units - Create and post the invoice - Change the product's standard price to 20. - Create a credit note without returning the delivered stock -> The cogs value on the credit note is 40 instead of 20 **Cause** While posting the credit note: https://github.com/odoo/odoo/bl
Original PR description
**Issue** A credit note created before returning any stock may compute an incorrect COGS value. **Steps to reproduce** - Create a product valued with AVCO and a standard price of 10 - Create and…
**Issue** A credit note created before returning any stock may compute an incorrect COGS value. **Steps to reproduce** - Create a product valued with AVCO and a standard price of 10 - Create and confirm a SO for 2 units - Create and post the invoice - Change the product's standard price to 20. - Create a credit note without returning the delivered stock -> The cogs value on the credit note is 40 instead of 20 **Cause** While posting the credit note: https://github.com/odoo/odoo/blob/844853be7956416c0cdcdeeb0d5f22422b528e5c/addons/sale/models/account_move.py#L62 https://github.com/odoo/odoo/blob/844853be7956416c0cdcdeeb0d5f22422b528e5c/addons/account/models/account_move.py#L5580 COGS lines are created: https://github.com/odoo/odoo/blob/844853be7956416c0cdcdeeb0d5f22422b528e5c/addons/stock_account/models/account_move.py#L46 which needs to compute the unit_price: https://github.com/odoo/odoo/blob/f715337f70bf7eaa8f084da6cd42d674d7a4bfe0/addons/stock_account/models/account_move.py#L132 which is initially computed from the original invoice line: https://github.com/odoo/odoo/blob/844853be7956416c0cdcdeeb0d5f22422b528e5c/addons/stock_account/models/account_move.py#L308-L317 However, the `sale_stock` override recomputes that value whenever the invoice line is linked to a sales order: https://github.com/odoo/odoo/blob/844853be7956416c0cdcdeeb0d5f22422b528e5c/addons/sale_stock/models/account_move.py#L173 https://github.com/odoo/odoo/blob/844853be7956416c0cdcdeeb0d5f22422b528e5c/addons/sale_stock/models/account_move.py#L212-L213 This computation will give the standard price since: - `is_returned` is True but no return move, which means there won't be any candidate: https://github.com/odoo/odoo/blob/844853be7956416c0cdcdeeb0d5f22422b528e5c/addons/stock_account/models/product.py#L921-L923 - As a result, `qty_valued` is zero: https://github.com/odoo/odoo/blob/844853be7956416c0cdcdeeb0d5f22422b528e5c/addons/stock_account/models/product.py#L933-L936 https://github.com/odoo/odoo/blob/844853be7956416c0cdcdeeb0d5f22422b528e5c/addons/stock_account/models/stock_valuation_layer.py#L172-L173 - The computation therefore falls back to the current standard price: https://github.com/odoo/odoo/blob/844853be7956416c0cdcdeeb0d5f22422b528e5c/addons/stock_account/models/product.py#L938-L946 opw-6369550
Before this commit, the default einvoice format was changed only when the partner was french and had a vat number, but we want to ease that condition and do it only if the partner is french. task-6303174 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
Before this commit, the default einvoice format was changed only when the partner was french and had a vat number, but we want to ease that condition and do it only if the partner is french. task-6303174 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
### Issue before the commit: During the import of Italian e-invoices, Pension Fund taxes (Cassa Previdenziale) linked to a 0% VAT rate with a specific exemption reason (Natura, e.g., N2.2) are ignored and not applied to the invoice lines. ### Steps to reproduce the issue: 1. Download Accounting and l10n_it 2. Go to vendor -> bills and import the bill in the ticket 3. Check that taxes are not imported as expected ### Cause of the issue: The system incorrectly used the Natura to search
Original PR description
### Issue before the commit: During the import of Italian e-invoices, Pension Fund taxes (Cassa Previdenziale) linked to a 0% VAT rate with a specific exemption reason (Natura, e.g., N2.2) are ignored and not applied to the invoice lines. ### Steps to reproduce the issue: 1. Download Accounting and l10n_it 2. Go to vendor -> bills and import the bill in the ticket 3. Check that taxes are not imported as expected ### Cause of the issue: The system incorrectly used the Natura to search for the Pension Fund tax itself. Fiscally, the Natura belongs to the related VAT, not the Pension Fund. This incorrect domain caused the tax search to fail. The Pension Fund tax should not have a Natura setted. ### Reason to introduce the fix: To correctly apply Pension Fund taxes to exempt invoice lines. Ticket [link](https://www.odoo.com/odoo/project.task/6357133) opw-6357133 Forward-Port-Of: odoo/odoo#275317
The mail.message/delete bus handler accessed selfMember?.seen_message_id.id with optional chaining only on selfMember, not on seen_message_id. When a member has never seen any message in a channel (seen_message_id is False), accessing .id threw 'TypeError: can't access property id, selfMember.seen_message_id is undefined', breaking message deletion for that user (e.g. deleting a message in a channel the user never opened. Add optional chaining on seen_message_id so the unread counter is simpl
Original PR description
The mail.message/delete bus handler accessed selfMember?.seen_message_id.id with optional chaining only on selfMember, not on seen_message_id. When a member has never seen any message in a channel (seen_message_id is False), accessing .id threw 'TypeError: can't access property id, selfMember.seen_message_id is undefined', breaking message deletion for that user (e.g. deleting a message in a channel the user never opened. Add optional chaining on seen_message_id so the unread counter is simply not decremented when no message has been seen yet. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
When preparing procurement values from a stock move, the project is retrieved from the sale order through: self.group_id.sale_id.project_id Users with Sales access set to "Own Documents Only" may not have read access to the originating sale order, causing an AccessError when editing manufacturing orders by adding components that use the MTO flow. The fix is to include sudo() for the project lookup, as editing a MO and should not depend on the user's SO visibility. Steps to Reproduce: 1
Original PR description
When preparing procurement values from a stock move, the project is retrieved from the sale order through: self.group_id.sale_id.project_id Users with Sales access set to "Own Documents Only" may not have read access to the originating sale order, causing an AccessError when editing manufacturing orders by adding components that use the MTO flow. The fix is to include sudo() for the project lookup, as editing a MO and should not depend on the user's SO visibility. Steps to Reproduce: 1. Turn on multi-step routes and unarchive the MTO route 2. Create a SO using a product that has a BOM and uses Manufacture/MTO route 3. Logged in as Marc Demo, open the MO and try to add a component. The component must also have the Manufacture/MTO route enabled. 4. You will get an access rights error upon save/confirm. Related Tickets: opw-6366029
When installing the module document_account_peppol, the user has the choice to import his Peppol invoices into the Documents app directly, but also to block the import in Accounting, by removing the Peppol import journal. In that last case, the Peppol application response flow is broken, the document model does not contain the necessary information to handle responses as the imported invoices do. (In stable) We took the decision to remove the ApplicationResponse service from users that bl
Original PR description
When installing the module document_account_peppol, the user has the choice to import his Peppol invoices into the Documents app directly, but also to block the import in Accounting, by removing the Peppol import journal. In that last case, the Peppol application response flow is broken, the document model does not contain the necessary information to handle responses as the imported invoices do. (In stable) We took the decision to remove the ApplicationResponse service from users that block the invoice import flow by removing the import journal. For PDP, the responses are required, but as the block is completely replaced in the view, and reuses the basic account_peppol condition for the required attribute, the account peppol purchase journal will always be required if the company is registered on Peppol/PDP. Nothing to do in 18.0. task-6191644
iOS devices currently display the first letter of the website name instead of a favicon when creating a shortcut. This commit adds the `apple-touch-icon` link tag referencing the favicon to ensure the icon displays correctly. This commit is a backport of [1], which was merged in master(saas-19.2). task-5427275 [1]: https://github.com/odoo/odoo/commit/2506fdfc49f1515aea7e715e9f6d66418a093401 Forward-Port-Of: odoo/odoo#277723
Original PR description
iOS devices currently display the first letter of the website name instead of a favicon when creating a shortcut. This commit adds the `apple-touch-icon` link tag referencing the favicon to ensure the icon displays correctly. This commit is a backport of [1], which was merged in master(saas-19.2). task-5427275 [1]: https://github.com/odoo/odoo/commit/2506fdfc49f1515aea7e715e9f6d66418a093401 Forward-Port-Of: odoo/odoo#277723
Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: . Add safe execution to the element before use focus() task-6409715 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: . Add safe execution to the element before use focus() task-6409715 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Miscellaneous changes
When a bus process restarts, every client on every database it serves loses its websocket at the same instant and immediately schedules a reconnection. Each database that comes back triggers a registry recompute server-side, so a tight reconnection window makes all of those recomputes land together and pile up on the freshly started process. The jitter added to each reconnection delay was only one second, far too narrow to break up that wave. Widen it to thirty seconds so the retries of the m
Original PR description
When a bus process restarts, every client on every database it serves loses its websocket at the same instant and immediately schedules a reconnection. Each database that comes back triggers a…
When a bus process restarts, every client on every database it serves loses its websocket at the same instant and immediately schedules a reconnection. Each database that comes back triggers a registry recompute server-side, so a tight reconnection window makes all of those recomputes land together and pile up on the freshly started process. The jitter added to each reconnection delay was only one second, far too narrow to break up that wave. Widen it to thirty seconds so the retries of the many clients fan out over a much wider window and the registry recomputes spread over time instead of colliding. Raise the ceiling on the retry delay to two minutes to match that wider spread, and drop the exponential growth factor: with a thirty-second jitter accumulating on every attempt, the delay already climbs on its own, so scaling it further only pushed clients toward the ceiling sooner without spreading them any better. 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
3 changes
Resolved issues and error corrections
Issue: Users in debug mode can access chatter's form and alter it. Steps to reproduce: Enter debug mode ('?debug=1'); Go into any chatter (ex: Sales) Send a message In the debug menu go in "Manage Messages" Select the message you just sent and you should be able to alter, who sent it, what is in the message, sent date,... Cause: The fields on the xml form are missing readonly, as this information should not be edited. Solution: Added the readonly in order for users to not change
Original PR description
Issue:
Users in debug mode can access chatter's form and alter it.
Steps to reproduce:
Enter debug mode ('?debug=1');
Go into any chatter (ex: Sales)
Send a message
In the debug menu go in "Manage Messages"
Select the message you just sent and you should be able to alter, who sent it, what is in the message, sent date,...
Cause:
The fields on the xml form are missing readonly, as this information should not be edited.
Solution:
Added the readonly in order for users to not change this data.
opw-6270043The earlier fix that base64-decodes the /pdf response missed one test on 17.0 whose mock returned raw PDF bytes instead of the JSON-decoded base64 string `NilveraClient.request()` actually returns. On Python <=3.13 `b64decode` silently produced garbage and the mimetype-only assertion stayed green; on Python 3.14 strict validation rejects the raw bytes with `binascii.Error: Incorrect padding`. Encode the fixture with `b64encode(...).decode()` so the mock matches the real API. Descript
Original PR description
The earlier fix that base64-decodes the /pdf response missed one test on 17.0 whose mock returned raw PDF bytes instead of the JSON-decoded base64 string `NilveraClient.request()` actually returns. On Python <=3.13 `b64decode` silently produced garbage and the mimetype-only assertion stayed green; on Python 3.14 strict validation rejects the raw bytes with `binascii.Error: Incorrect padding`. Encode the fixture with `b64encode(...).decode()` so the mock matches the real API. 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
Miscellaneous changes
_stock_account_anglo_saxon_reconcile_valuation() scans a whole invoice on every call and only reconciles at the end, but _validate_accounting_entries() calls it once per product. The invoice is therefore re-scanned as many times as there are products. This can lead to performance issues when the invoices contain thousands of lines. Steps to reproduce: - use anglo-saxon accounting with automated inventory valuation - confirm a sale order holding a few thousand distinct products -
Original PR description
_stock_account_anglo_saxon_reconcile_valuation() scans a whole invoice on every call and only reconciles at the end, but _validate_accounting_entries() calls it once per product. The invoice is…
_stock_account_anglo_saxon_reconcile_valuation() scans a whole invoice on every call and only reconciles at the end, but _validate_accounting_entries() calls it once per product. The invoice is therefore re-scanned as many times as there are products. This can lead to performance issues when the invoices contain thousands of lines. Steps to reproduce: - use anglo-saxon accounting with automated inventory valuation - confirm a sale order holding a few thousand distinct products - invoice it, then validate its delivery => performance issue Group the products by their related invoices and reconcile each group in one call. Delivering 20 products against a 5000 line invoice goes from 63s to 9.7s. On the reported customer database a delivery of 197 products, against an invoice grouping 27 orders and carrying 17822 journal items, goes from 369s to 16s. Benchmark: | Invoice Lines | Before | After | |--------------:|-------:|------:| | 100 | 1.9s | 0.7s | | 1 000 | 13.0s | 2.0s | | 5 000 | 63.3s | 9.7s | opw-6388781