Daily updates from Odoo
Tuesday, August 4, 2026
341 changes
27 changes
New functionality added to Odoo
Slovak entities are identified by three separate numbers: IČO, IČ DPH and DIČ. The first two are already on res.partner as `company_registry` and `vat`. The DIČ was only defined on res.company by `l10n_sk`, so it could not be recorded for customers and vendors. It identifies Slovak companies on business documents, and Peppol EAS 0245 designates it. With mandatory B2B e-invoicing in Slovakia from January 2027 and Peppol support coming in #275798, it has to live on res.partner. `income_tax_id`
Original PR description
Slovak entities are identified by three separate numbers: IČO, IČ DPH and DIČ. The first two are already on res.partner as `company_registry` and `vat`. The DIČ was only defined on res.company by `l10n_sk`, so it could not be recorded for customers and vendors. It identifies Slovak companies on business documents, and Peppol EAS 0245 designates it. With mandatory B2B e-invoicing in Slovakia from January 2027 and Peppol support coming in #275798, it has to live on res.partner. `income_tax_id` on res.company becomes related to it, mirroring vat and company_registry since they are related as well. Existing values are moved by a post init hook. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#280178
Enhancements to existing features
Added placeholder image for the donation product. Task-6361612 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
Added placeholder image for the donation product. Task-6361612 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#278655
Original PR description
Forward-Port-Of: odoo/odoo#278655
We update the IoT Box version, so that it follow the new saas version (19.4). Forward-Port-Of: odoo/odoo#278588
Original PR description
We update the IoT Box version, so that it follow the new saas version (19.4). Forward-Port-Of: odoo/odoo#278588
Pycups has an issue where it can raise an error (1280) meanwhile the status is a success. We don't want to see a traceback in such case, so we skip logging in this case.
Original PR description
Pycups has an issue where it can raise an error (1280) meanwhile the status is a success. We don't want to see a traceback in such case, so we skip logging in this case.
Resolved issues and error corrections
Posting a message bumps discuss_channel.last_interest_dt. _update_last_interest_dt writes it in a separate transaction so the channel row lock is released almost instantly, letting parallel posters proceed instead of piling up on that hot row and crashing with: could not serialize access due to concurrent update However, when the main transaction also writes the channel row (e.g. im_livechat sets livechat_failure in _message_post_after_hook), it holds the row lock for the whole request
Original PR description
Posting a message bumps discuss_channel.last_interest_dt. _update_last_interest_dt writes it in a separate transaction so the channel row lock is released almost instantly, letting parallel posters…
Posting a message bumps discuss_channel.last_interest_dt. _update_last_interest_dt writes it in a separate transaction so the channel row lock is released almost instantly, letting parallel posters proceed instead of piling up on that hot row and crashing with:
could not serialize access due to concurrent update
However, when the main transaction also writes the channel row (e.g. im_livechat sets livechat_failure in _message_post_after_hook), it holds the row lock for the whole request. The separate transaction then blocks on that lock until timeout. It is not even reported as a deadlock, since the main transaction is not itself waiting on anything, so the request just hangs.
Update last_interest_dt at the end of the post flow, in _message_post_after_hook, once all the channel writes it may trigger have been done. There, if the channel row is already dirty in the main transaction, write last_interest_dt on that transaction rather than a separate one: its row is already locked, so a separate transaction has nothing to gain and would only block.
task-6321278
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prIssue: --- If a product template has dynamic attributes, some variants might not exist. For those variants, we are showing wrong stock in the website. To reproduce: 1- Create a product with a dynamic attribute and two values. 2- Publish the product and uncheck sell when out-of-stock and check show product when the qty is less than 5. 3- Create a purchase order with qty = 4 for the first value, so a variant is created for it. 4- Go to the website shop. Open the product. 4 available qty i
Original PR description
Issue: --- If a product template has dynamic attributes, some variants might not exist. For those variants, we are showing wrong stock in the website. To reproduce: 1- Create a product with a dynamic attribute and two values. 2- Publish the product and uncheck sell when out-of-stock and check show product when the qty is less than 5. 3- Create a purchase order with qty = 4 for the first value, so a variant is created for it. 4- Go to the website shop. Open the product. 4 available qty in stock is shown for the first variant which is correct. 5- Select 2nd variant. As you see, still 4 available qty is shown which is wrong. As the out-of-stock sale is unchecked, an out-of-stock warning should be shown. Cause and Fix: --- This is due to `isMainProduct` being always False when `product_id` is not set which makes `free_qty` and `out_of_stock` not to be updated. opw-6237602 Forward-Port-Of: odoo/odoo#279970 Forward-Port-Of: odoo/odoo#273104
Before this commit, when a product had a multi choice attribute with only one option, it was not possible to configure the product in the POS or in the self. This is a problem since multi choice are different from other attribute display type because their options are opttional. The user should thus be able to select if he wants the option or not so we should display the configurator even if there is only one option. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.
Original PR description
Before this commit, when a product had a multi choice attribute with only one option, it was not possible to configure the product in the POS or in the self. This is a problem since multi choice are different from other attribute display type because their options are opttional. The user should thus be able to select if he wants the option or not so we should display the configurator even if there is only one option. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#271287
Restore the previous behavior by calling `checkAccessRight()` without awaiting it during `PosStore.setup()`. This prevents the POS startup from being blocked while the access check is running. This fixes PoS startup and offline fallback tours timing out while waiting for the "Continue with limited functionality" dialog. Runbot Error-[944421](https://runbot.odoo.com/odoo/error/944421) Forward-Port-Of: odoo/odoo#279792 Forward-Port-Of: odoo/odoo#278628
Original PR description
Restore the previous behavior by calling `checkAccessRight()` without awaiting it during `PosStore.setup()`. This prevents the POS startup from being blocked while the access check is running. This fixes PoS startup and offline fallback tours timing out while waiting for the "Continue with limited functionality" dialog. Runbot Error-[944421](https://runbot.odoo.com/odoo/error/944421) Forward-Port-Of: odoo/odoo#279792 Forward-Port-Of: odoo/odoo#278628
When a product with no attributes is sold, the description_picking field of the stock.move is empty. Steps to reproduce: ------------------- * Create a product with no attributes * Create a sale order with this product * Confirm the sale order > Observation: The description_picking field of the stock.move is empty The issue was originally reported because the e-Waybill in India had an empty description for the product. Why the fix: ------------ When trying to avoid duplicating th
Original PR description
When a product with no attributes is sold, the description_picking field of the stock.move is empty. Steps to reproduce: ------------------- * Create a product with no attributes * Create a sale order with this product * Confirm the sale order > Observation: The description_picking field of the stock.move is empty The issue was originally reported because the e-Waybill in India had an empty description for the product. Why the fix: ------------ When trying to avoid duplicating the product name, we should first check that it would not result in an empty description picking. opw-6318785 Forward-Port-Of: odoo/odoo#279483 Forward-Port-Of: odoo/odoo#275248
Currently, when using the quick create form to create a calendar.event, if you set up the event for the whole day the show_as field will always be saved as free no matter the value set by the user. Steps to reproduce: ------------------- * Open Calendar app * Select the a slot that corresponds to a whole day * Ensure all day is ticked * Change 'Available' to 'Busy' * Save * Select the slot and select Edit > Observe that the status is showing 'Available' Why the fix: ------------
Original PR description
Currently, when using the quick create form to create a calendar.event, if you set up the event for the whole day the show_as field will always be saved as free no matter the value set by the user.…
Currently, when using the quick create form to create a calendar.event, if you set up the event for the whole day the show_as field will always be saved as free no matter the value set by the user. Steps to reproduce: ------------------- * Open Calendar app * Select the a slot that corresponds to a whole day * Ensure all day is ticked * Change 'Available' to 'Busy' * Save * Select the slot and select Edit > Observe that the status is showing 'Available' Why the fix: ------------ The defaults should be: all day = free, not all day = busy However those values should still remain modifyable. This commit https://github.com/odoo/odoo/commit/62ecdba6dc963ddcdfca9e2e924ae5f6ca34e5de states: > When the user toggles allDay within the edit form, the availability is recomputed (this behavior matches google calendar) For the normal form itself the onchange triggers and behaves as stated. And if the user decides to change the show_as value it will save its choice correctly. For the quick create form, the onchange also triggers correcly. Meaning the velue of show_as is recomputed depending on allday. However upon saving, the value of show_as is bypassed if allday is true but it should keep the value selected by the user. opw-6326575 Forward-Port-Of: odoo/odoo#273567
### Steps to reproduce: - Create 2 companies: c1, c2 - Create 2 storable products: P, Comp - In c1 update the available qty of P to 10 units and its cost to 50 - In c2 create a kit bom for P: 1 x Comp - With c1 > Accounting > Review > inventory > Inventory Valuation #### > The total value of Super product is 0 instead of 500 ### Cause of the issue: The total value of the product will be set to 0 since the `qty_available` of the product is incorrectly computed to be 0: https://gith
Original PR description
### Steps to reproduce: - Create 2 companies: c1, c2 - Create 2 storable products: P, Comp - In c1 update the available qty of P to 10 units and its cost to 50 - In c2 create a kit bom for P: 1 x…
### Steps to reproduce: - Create 2 companies: c1, c2 - Create 2 storable products: P, Comp - In c1 update the available qty of P to 10 units and its cost to 50 - In c2 create a kit bom for P: 1 x Comp - With c1 > Accounting > Review > inventory > Inventory Valuation #### > The total value of Super product is 0 instead of 500 ### Cause of the issue: The total value of the product will be set to 0 since the `qty_available` of the product is incorrectly computed to be 0: https://github.com/odoo/odoo/blob/cb7b3de6cea07464bcadd1325f52533d34ce09bc/addons/stock_account/models/product.py#L240-L243 This happens because the `_find_bom` used in the override of the `_compute_quantities_dict` in mrp does not consider take the contextual company into account: https://github.com/odoo/odoo/blob/cb7b3de6cea07464bcadd1325f52533d34ce09bc/addons/mrp/models/product.py#L271-L289 and hence considers incorrectly that the product is a kit. ### Note: We make the same company dependency as in the `is_kits` computation: https://github.com/odoo/odoo/blob/cb7b3de6cea07464bcadd1325f52533d34ce09bc/addons/mrp/models/product.py#L41-L47 opw-6361690 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279227 Forward-Port-Of: odoo/odoo#276306
### Steps to reproduce: - Install `sale_mrp` and `l10n_ke_edi_oscu_stock` - Set company country to be 'Kenya' - Run the `test_kit_cogs_entry_with_delivery_line_removal` test > odoo.exceptions.UserError: Cannot create an invoice. No items are available to invoice. ### Cause of Issue: The test validates COGS entries for a kit by creating a sale order, then generating an invoice. When `l10n_ke_edi_oscu_stock` is installed, it overrides the `invoice_policy` of all storable products for Ke
Original PR description
### Steps to reproduce: - Install `sale_mrp` and `l10n_ke_edi_oscu_stock` - Set company country to be 'Kenya' - Run the `test_kit_cogs_entry_with_delivery_line_removal` test >…
### Steps to reproduce: - Install `sale_mrp` and `l10n_ke_edi_oscu_stock` - Set company country to be 'Kenya' - Run the `test_kit_cogs_entry_with_delivery_line_removal` test > odoo.exceptions.UserError: Cannot create an invoice. No items are available to invoice. ### Cause of Issue: The test validates COGS entries for a kit by creating a sale order, then generating an invoice. When `l10n_ke_edi_oscu_stock` is installed, it overrides the `invoice_policy` of all storable products for Kenyan companies to `'delivery'`. https://github.com/odoo/enterprise/blob/82b736a283ed5ab3ad431a1cdbcedc1b8e3c2d7c/l10n_ke_edi_oscu_stock/models/product.py#L16-L21 Because the test removes a required component from the picking, the delivered quantity of the kit is computed as 0. Since the kit's invoice policy is dynamically forced to `'delivery'` by the localization, calling `_create_invoices()` raises a `UserError` as there are no delivered items to invoice, failing the test on runbot. ### Fix: Ensure that kit product use an invoicing policy of 'Ordered Quantities' rather than the default 'Delivered Quantities'. This allows the test to proceed and correctly evaluate the core COGS computation logic it was designed to check. runbot-243342 Forward-Port-Of: odoo/odoo#279450
`subscribe message is sent first` queues two events while disconnected, then triggered a subscription with `addChannel`. But `addChannel` also sends `BUS:START`: the worker reconnected immediately, flushed the wait queue and sent the subscription, so the assertion that nothing goes out while disconnected failed. Use `forceUpdateChannels` to schedule the subscription without touching the connection state, and await each send so the messages are posted before the outgoing batch delay is flushed
Original PR description
`subscribe message is sent first` queues two events while disconnected, then triggered a subscription with `addChannel`. But `addChannel` also sends `BUS:START`: the worker reconnected immediately, flushed the wait queue and sent the subscription, so the assertion that nothing goes out while disconnected failed. Use `forceUpdateChannels` to schedule the subscription without touching the connection state, and await each send so the messages are posted before the outgoing batch delay is flushed. runbot-944123 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
Replace company_id.country_code with the partner's country in the cron domain, as it is not searchable (not stored). task-6416779 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
Replace company_id.country_code with the partner's country in the cron domain, as it is not searchable (not stored). task-6416779 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Steps to reproduce: 1. install mail 2. Send a voice message to anyone from the discuss app 3. Open the ui in mobile and see the voice messege duration Issue: - time is showing in two lines Solution: - Adjust the spacing of the voice player controls for small screens using responsive Bootstrap utility classes and prevent the duration text from shrinking, ensuring it remains on a single line while preserving the existing layout on larger screens. <table width="100%"> <tr> <th
Original PR description
Steps to reproduce:
1. install mail
2. Send a voice message to anyone from the discuss app
3. Open the ui in mobile and see the voice messege duration
Issue:
- time is showing in two lines
Solution:
- Adjust the spacing of the voice player controls for small screens using responsive Bootstrap utility classes and prevent the duration text from shrinking, ensuring it remains on a single line while preserving the existing layout on larger screens.
<table width="100%">
<tr>
<th>Before</th>
<th>After</th>
</tr>
<tr>
<td align="center">
<img alt="After" src="https://github.com/user-attachments/assets/98f41d1a-9082-4d5c-a34b-c9181e643e0a">
</td>
<td align="center">
<img alt="Before" src="https://github.com/user-attachments/assets/0f879988-b2e6-46c9-ba5a-0f935fde40ec">
</td>
</tr>
</table>
opw-6328609
Forward-Port-Of: odoo/odoo#277170
Forward-Port-Of: odoo/odoo#271768Problem: When adding a caption to an image, typing text, then undoing and redoing does not restore the caption content. Cause: The caption used a native `<input>` element whose content is managed by the browser, not the editor's history stack. While redo could restore the input element itself, its content was lost since the editor never tracked it. Solution: Replace the `<input>` with a `contenteditable` `<span>` so the editor manages its content as part of the DOM history, enabling ful
Original PR description
Problem: When adding a caption to an image, typing text, then undoing and redoing does not restore the caption content. Cause: The caption used a native `<input>` element whose content is managed by the browser, not the editor's history stack. While redo could restore the input element itself, its content was lost since the editor never tracked it. Solution: Replace the `<input>` with a `contenteditable` `<span>` so the editor manages its content as part of the DOM history, enabling full undo/redo. Changes: - Use a contenteditable `<span>` instead of `<input>` for caption editing - Prevent pasting HTML inside the span (plain text only) - Limit caption content to 100 characters - Disable power box, toolbar, and paragraph insertion inside the span task-6219868 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279771 Forward-Port-Of: odoo/odoo#267211
Issue: Outstanding credits/debits from a branch don't appear on the main company and inversely. Cause : From odoo/odoo#255875 outstanding credits/debits are limited by company to prevent different company issues on validation. However, this error is raised for `account.move` having different root companies. Which allow move from different branches of the same company. Steps to reproduce: - create a company and a branch - in the main company create a customer payment and valid it - in
Original PR description
Issue: Outstanding credits/debits from a branch don't appear on the main company and inversely. Cause : From odoo/odoo#255875 outstanding credits/debits are limited by company to prevent different company issues on validation. However, this error is raised for `account.move` having different root companies. Which allow move from different branches of the same company. Steps to reproduce: - create a company and a branch - in the main company create a customer payment and valid it - in the branch, create an invoice for the same customer and confirm it Current behavior: - the outstanding payment from the main company doesn't appear on the branch invoice, However, it's possible to reconcile it from the Journal entry view Expected behavior: - the outstanding payment from the main company appears on the branch invoice, opw-6140689 Forward-Port-Of: odoo/odoo#280018 Forward-Port-Of: odoo/odoo#262260
Steps to reproduce: - install populate and any module with populate blueprint in 2 DBs - populate both of them using the same seed - notice that they still produce different records Problem: - using the same seed, 2 DBs should ALWAYS produce the same records - the problem occurs because `Faker` instances were not seeded from the passed seed or the populate session's "random" seed value Fix: - make each `Faker` instance to use the already-seeded random generator. - which will make g
Original PR description
Steps to reproduce: - install populate and any module with populate blueprint in 2 DBs - populate both of them using the same seed - notice that they still produce different records Problem: - using the same seed, 2 DBs should ALWAYS produce the same records - the problem occurs because `Faker` instances were not seeded from the passed seed or the populate session's "random" seed value Fix: - make each `Faker` instance to use the already-seeded random generator. - which will make generated fake records deterministic when using the same seed.
..., pos_restaurant, pos_self_order, pos_urban_piper --- During the refactor of the receipt printing system, some CSS classes were no longer loaded with preparation tickets. As a result, preparation tickets lost part of their original styling. To restore the expected rendering, ensure all required classes are properly loaded while keeping the loading minimal. Additionally, some receipt data were missing after the refactor and some UI elements could be improved. This commit restores t
Original PR description
..., pos_restaurant, pos_self_order, pos_urban_piper --- During the refactor of the receipt printing system, some CSS classes were no longer loaded with preparation tickets. As a result, preparation tickets lost part of their original styling. To restore the expected rendering, ensure all required classes are properly loaded while keeping the loading minimal. Additionally, some receipt data were missing after the refactor and some UI elements could be improved. This commit restores the missing data and improves the overall UI. It also fixes an issue where customer notes were not printed on the receipt. Templates checked: * point_of_sale.pos_order_change_receipt * point_of_sale.pos_order_change_receipt_line --- Task: https://www.odoo.com/odoo/project/1737/tasks/6133403 Refacto: https://github.com/odoo/odoo/pull/244395 Forward-Port-Of: odoo/odoo#276815 Forward-Port-Of: odoo/odoo#267161
**Description of the issue/feature this PR addresses:** `test_search_date_category` is failing across runbot builds Remove the blanket deletion of all repair orders at the start of test_search_date_category and replace the exact count assertion with assertIn. This avoids interfering with other test data and makes the test resilient to pre-existing records in the database. **Current behavior before PR:** ``` ERROR: TestRepair.test_search_date_category Traceback (most recent call last):
Original PR description
**Description of the issue/feature this PR addresses:** `test_search_date_category` is failing across runbot builds Remove the blanket deletion of all repair orders at the start of…
**Description of the issue/feature this PR addresses:**
`test_search_date_category` is failing across runbot builds
Remove the blanket deletion of all repair orders at the start of test_search_date_category and replace the exact count assertion with assertIn. This avoids interfering with other test data and makes the test resilient to pre-existing records in the database.
**Current behavior before PR:**
```
ERROR: TestRepair.test_search_date_category
Traceback (most recent call last):
File "/data/build/odoo/addons/repair/tests/test_repair.py", line 915, in test_search_date_category
self.env['repair.order'].search([]).unlink()
File "/data/build/odoo/addons/rating/models/mail_thread.py", line 21, in unlink
result = super().unlink()
^^^^^^^^^^^^^^^^
File "/data/build/odoo/addons/mail/models/mail_thread.py", line 391, in unlink
res = super(MailThread, self).unlink()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/build/odoo/addons/mail/models/models.py", line 46, in unlink
result = super().unlink()
^^^^^^^^^^^^^^^^
File "/data/build/odoo/odoo/orm/models.py", line 4131, in unlink
func(self)
File "/data/build/odoo/addons/repair/models/repair.py", line 421, in _unlink_except_confirmed
repairs_to_cancel.action_repair_cancel()
File "/data/build/enterprise/quality_repair/models/repair.py", line 114, in action_repair_cancel
res = super().action_repair_cancel()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/build/odoo/addons/repair/models/repair.py", line 475, in action_repair_cancel
raise UserError(_("You cannot cancel a Repair Order that's already been completed"))
odoo.exceptions.UserError: You cannot cancel a Repair Order that's already been completed
```
**Desired behavior after PR is merged:**
`test_search_date_category` passes
opw-[4998413](https://www.odoo.com/odoo/my-tasks/4998413)
runbot.build.error-[231146](https://runbot.odoo.com/odoo/runbot.build.error/231146)
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#267852### Issue before this commit: When importing an electronic invoice from SDI that is failing with an exception, the resulting account.move record was saved in the "Miscellaneous Operations" journal instead of the correct one (Vendor Bills), even though the move_type itself was correct. ### Steps to reproduce the issue: Pre steps: you need to have access to https://iap-services-test.odoo.com/odoo 1. Download Accounting and l10n_it 2. Go to Settings > Companies and set the VAT of IT company
Original PR description
### Issue before this commit: When importing an electronic invoice from SDI that is failing with an exception, the resulting account.move record was saved in the "Miscellaneous Operations" journal…
### Issue before this commit: When importing an electronic invoice from SDI that is failing with an exception, the resulting account.move record was saved in the "Miscellaneous Operations" journal instead of the correct one (Vendor Bills), even though the move_type itself was correct. ### Steps to reproduce the issue: Pre steps: you need to have access to https://iap-services-test.odoo.com/odoo 1. Download Accounting and l10n_it 2. Go to Settings > Companies and set the VAT of IT company the same as the one in the xml 3. Go to Settings > Italian Electronic Invoicing and select Test 4. Go into the code and insert an Exception inside the function _l10n_it_edi_import_invoice after self.move_type = move_type (or create any type of exception from the user interface) 5. Go to IAP service into IT EDI app and see that your company is there as user 6. Click into the record > receive move button > upload your xml > create 7. Go to your DB > Scheduled Actions > filter with IT > IT EDI: Receive invoices from the SdI > Run Manually 8. Go to Journal entries, remove the filter and find your imported bill 9. You can see it was inserted into the Miscellaneous Operations Journal instead of a Vendor Bill Journal ### Cause of the issue: The move is created inside a savepoint context manager, designed so that even if parsing fails, an empty move with the attachment still remains. The problem is that if the exception is raised, the savepoint rollback undoes everything that follows, but the journal was already determined before the correct move_type was known, leaving the move in the wrong default journal. ### Reason to introduce the fix: The fix is needed to ensure that, regardless of where parsing fails, the move's journal is correctly set even if an exception occurs so that it is possible to find the move in the correct section even if not imported correctly. opw-6397712 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279871 Forward-Port-Of: odoo/odoo#278111
Purpose of this PR: - On double click, opening the toolbar is delayed by 300ms to prevent flickering before a potential triple click. - However, mouseup was re-enabling selection tracking (onSelectionChangeActive = true) before the 300ms delay finished. Because browser selectionchange events are dispatched asynchronously after mouseup, they triggered updateToolbar() immediately, bypassing the 300ms delay. - This fix re-enables selection tracking only after the 300ms debounced update actuall
Original PR description
Purpose of this PR: - On double click, opening the toolbar is delayed by 300ms to prevent flickering before a potential triple click. - However, mouseup was re-enabling selection tracking (onSelectionChangeActive = true) before the 300ms delay finished. Because browser selectionchange events are dispatched asynchronously after mouseup, they triggered updateToolbar() immediately, bypassing the 300ms delay. - This fix re-enables selection tracking only after the 300ms debounced update actually finishes. runbot-941543 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279826 Forward-Port-Of: odoo/odoo#278025
### Issue: When a `stock.move.line` is manually added to a component move of a Manufacturing Order via the debug View button, it is not linked to the MO This causes the line to appear without a `production_id` in Move History (shown in gray in 18.3+ instead of colored) ### Cause: `production_id` is set on move lines in `_action_assign`, overridden in `mrp` to propagate MO-specific data: https://github.com/odoo/odoo/blob/e8d4ea2dc71109e9afc5b894c9359bcfc08295ae/addons/mrp/models/stock_mov
Original PR description
### Issue: When a `stock.move.line` is manually added to a component move of a Manufacturing Order via the debug View button, it is not linked to the MO This causes the line to appear without a…
### Issue: When a `stock.move.line` is manually added to a component move of a Manufacturing Order via the debug View button, it is not linked to the MO This causes the line to appear without a `production_id` in Move History (shown in gray in 18.3+ instead of colored) ### Cause: `production_id` is set on move lines in `_action_assign`, overridden in `mrp` to propagate MO-specific data: https://github.com/odoo/odoo/blob/e8d4ea2dc71109e9afc5b894c9359bcfc08295ae/addons/mrp/models/stock_move.py#L352-L358 In the normal flow, `_action_assign` is called by `_action_confirm` on the `stock.move`: https://github.com/odoo/odoo/blob/737e28b9c8609d488d93ce7ce05941ff93779e04/addons/stock/models/stock_move.py#L1644-L1646 But when a line is added manually, the move is already created with state `assigned`, so `_action_confirm` skips the call and `_action_assign` is never executed ### Fix: Setting `production_id` in `_action_assign` was incorrectly placed — there is no reason to set it during move assignment Moving it to the move line creation avoids the issue entirely and removes the dependency on a code path that may not be triggered ### Steps to reproduce: - Install `mrp` - Create a BoM for a tracked product with 2 tracked components - Enable Developer mode - Create a Manufacturing Order for the product - Unhide the View button on a component move and click it - Add a new line for the first component (qty: 1) - Confirm and Produce All the MO - Go to Inventory > Reporting > Move History - Add `production_id` via Studio (or check line color in 18.3+) Before the fix, the manually added line has no `production_id` (and in 18.3+ the line is gray instead of colored) opw-6250911 Forward-Port-Of: odoo/odoo#280193 Forward-Port-Of: odoo/odoo#272035
We don’t need the onchange hack anymore after the orm fix: odoo/pull/273404
Original PR description
We don’t need the onchange hack anymore after the orm fix: odoo/pull/273404
When selecting a new microphone or camera in the `Voice & Video settings` outside an active meeting, the browser was not asking for permission immediately. This caused Firefox (which enforces per device permissions) to reprompt when the meeting started. This fix pre-authorizes the selected device, so Firefox prompts at selection time rather than when starting a meeting. task-6175062 Forward-Port-Of: odoo/odoo#280201 Forward-Port-Of: odoo/odoo#277730
Original PR description
When selecting a new microphone or camera in the `Voice & Video settings` outside an active meeting, the browser was not asking for permission immediately. This caused Firefox (which enforces per device permissions) to reprompt when the meeting started. This fix pre-authorizes the selected device, so Firefox prompts at selection time rather than when starting a meeting. task-6175062 Forward-Port-Of: odoo/odoo#280201 Forward-Port-Of: odoo/odoo#277730
Miscellaneous changes
When generating the Sales Report or Session Report with a large number of orders (1000+), the report computation could take several minutes or fail entirely with cursor closed errors. This was mainly caused by multiple inefficient ORM patterns, such as repeated searches inside nested loops and unnecessary recordset instantiations. This commit optimizes the report generation logic by: - Avoiding repeated searches inside loops (e.g. account payments per session) - Using `_search` instead of `
Original PR description
When generating the Sales Report or Session Report with a large number of orders (1000+), the report computation could take several minutes or fail entirely with cursor closed errors. This was mainly…
When generating the Sales Report or Session Report with a large number of orders (1000+), the report computation could take several minutes or fail entirely with cursor closed errors. This was mainly caused by multiple inefficient ORM patterns, such as repeated searches inside nested loops and unnecessary recordset instantiations. This commit optimizes the report generation logic by: - Avoiding repeated searches inside loops (e.g. account payments per session) - Using `_search` instead of `search` where only record ids are required - Grouping and caching session-related records (payments, moves, cash moves) - Reducing redundant ORM calls and Python-level iterations - Preserving the exact report output structure and values The returned data remains unchanged; only record ordering may differ due to optimized iteration and grouping. As a result, report generation time is significantly reduced and the report can be generated reliably even with very large order counts. task-5452734 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279413 Forward-Port-Of: odoo/odoo#241828
26 changes
Enhancements to existing features
Currently, Peppol product detection relies strictly on barcode or default_code matching, which fails when vendors use their own codes. Accurate product identification is essential before running the predictive model (for taxes/accounts) and is a strict prerequisite for Purchase Orders matching to function correctly. This PR makes the product matching relies on the Vendor Product Code as the first priority ( SellersItemIdentification or StandardItemIdentification or BuyersItemIdentification
Original PR description
Currently, Peppol product detection relies strictly on barcode or default_code matching, which fails when vendors use their own codes. Accurate product identification is essential before running the predictive model (for taxes/accounts) and is a strict prerequisite for Purchase Orders matching to function correctly. This PR makes the product matching relies on the Vendor Product Code as the first priority ( SellersItemIdentification or StandardItemIdentification or BuyersItemIdentification ) task-6171251 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262801
Forward-Port-Of: odoo/odoo#278655
Original PR description
Forward-Port-Of: odoo/odoo#278655
We update the IoT Box version, so that it follow the new saas version (19.4). Forward-Port-Of: odoo/odoo#278588
Original PR description
We update the IoT Box version, so that it follow the new saas version (19.4). Forward-Port-Of: odoo/odoo#278588
this commit move the save order button next to the action button. task-id: 6275576 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
this commit move the save order button next to the action button. task-id: 6275576 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Resolved issues and error corrections
When a product with no attributes is sold, the description_picking field of the stock.move is empty. Steps to reproduce: ------------------- * Create a product with no attributes * Create a sale order with this product * Confirm the sale order > Observation: The description_picking field of the stock.move is empty The issue was originally reported because the e-Waybill in India had an empty description for the product. Why the fix: ------------ When trying to avoid duplicating th
Original PR description
When a product with no attributes is sold, the description_picking field of the stock.move is empty. Steps to reproduce: ------------------- * Create a product with no attributes * Create a sale order with this product * Confirm the sale order > Observation: The description_picking field of the stock.move is empty The issue was originally reported because the e-Waybill in India had an empty description for the product. Why the fix: ------------ When trying to avoid duplicating the product name, we should first check that it would not result in an empty description picking. opw-6318785 Forward-Port-Of: odoo/odoo#279483 Forward-Port-Of: odoo/odoo#275248
When selecting a new microphone or camera in the `Voice & Video settings` outside an active meeting, the browser was not asking for permission immediately. This caused Firefox (which enforces per device permissions) to reprompt when the meeting started. This fix pre-authorizes the selected device, so Firefox prompts at selection time rather than when starting a meeting. task-6175062 Forward-Port-Of: odoo/odoo#280045 Forward-Port-Of: odoo/odoo#277730
Original PR description
When selecting a new microphone or camera in the `Voice & Video settings` outside an active meeting, the browser was not asking for permission immediately. This caused Firefox (which enforces per device permissions) to reprompt when the meeting started. This fix pre-authorizes the selected device, so Firefox prompts at selection time rather than when starting a meeting. task-6175062 Forward-Port-Of: odoo/odoo#280045 Forward-Port-Of: odoo/odoo#277730
Currently, when using the quick create form to create a calendar.event, if you set up the event for the whole day the show_as field will always be saved as free no matter the value set by the user. Steps to reproduce: ------------------- * Open Calendar app * Select the a slot that corresponds to a whole day * Ensure all day is ticked * Change 'Available' to 'Busy' * Save * Select the slot and select Edit > Observe that the status is showing 'Available' Why the fix: ------------
Original PR description
Currently, when using the quick create form to create a calendar.event, if you set up the event for the whole day the show_as field will always be saved as free no matter the value set by the user.…
Currently, when using the quick create form to create a calendar.event, if you set up the event for the whole day the show_as field will always be saved as free no matter the value set by the user. Steps to reproduce: ------------------- * Open Calendar app * Select the a slot that corresponds to a whole day * Ensure all day is ticked * Change 'Available' to 'Busy' * Save * Select the slot and select Edit > Observe that the status is showing 'Available' Why the fix: ------------ The defaults should be: all day = free, not all day = busy However those values should still remain modifyable. This commit https://github.com/odoo/odoo/commit/62ecdba6dc963ddcdfca9e2e924ae5f6ca34e5de states: > When the user toggles allDay within the edit form, the availability is recomputed (this behavior matches google calendar) For the normal form itself the onchange triggers and behaves as stated. And if the user decides to change the show_as value it will save its choice correctly. For the quick create form, the onchange also triggers correcly. Meaning the velue of show_as is recomputed depending on allday. However upon saving, the value of show_as is bypassed if allday is true but it should keep the value selected by the user. opw-6326575 Forward-Port-Of: odoo/odoo#273567
Steps to reproduce: - Install `l10n_sa_edi` and `Accounting`> Change Company - Accounting > Customers > Invoices > Select an invoice > Click `Print` - `ValueError: can only parse strings` When printing a simplified Saudi invoice, the QR code is generated from the invoice XML. If the invoice has no taxes, `_l10n_sa_generate_zatca_template()` returns an error instead of the XML. The QR code generation tried to parse this error as XML, which caused a `ValueError: can only parse strings` an
Original PR description
Steps to reproduce: - Install `l10n_sa_edi` and `Accounting`> Change Company - Accounting > Customers > Invoices > Select an invoice > Click `Print` - `ValueError: can only parse strings` When printing a simplified Saudi invoice, the QR code is generated from the invoice XML. If the invoice has no taxes, `_l10n_sa_generate_zatca_template()` returns an error instead of the XML. The QR code generation tried to parse this error as XML, which caused a `ValueError: can only parse strings` and hid the actual reason for the failure. This commit checks for the error before generating the QR code and raises the original Error so the user sees the correct validation message. opw-6372454 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
When 2 workers try to load at the same time a registry that needs to be updated, one of them will deadlock while waiting on the exclusive lock. In such a case, instead of logging and error, we want to log a warning and retry. The retry will block at the shared lock and avoid additional deadlocks. We cannot just raise ConcurrencyError because the HTTP server instantiates the registry before calling `retrying`. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/su
Original PR description
When 2 workers try to load at the same time a registry that needs to be updated, one of them will deadlock while waiting on the exclusive lock. In such a case, instead of logging and error, we want to log a warning and retry. The retry will block at the shared lock and avoid additional deadlocks. We cannot just raise ConcurrencyError because the HTTP server instantiates the registry before calling `retrying`. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
### Steps to reproduce: - Install `sale_mrp` and `l10n_ke_edi_oscu_stock` - Set company country to be 'Kenya' - Run the `test_kit_cogs_entry_with_delivery_line_removal` test > odoo.exceptions.UserError: Cannot create an invoice. No items are available to invoice. ### Cause of Issue: The test validates COGS entries for a kit by creating a sale order, then generating an invoice. When `l10n_ke_edi_oscu_stock` is installed, it overrides the `invoice_policy` of all storable products for Ke
Original PR description
### Steps to reproduce: - Install `sale_mrp` and `l10n_ke_edi_oscu_stock` - Set company country to be 'Kenya' - Run the `test_kit_cogs_entry_with_delivery_line_removal` test >…
### Steps to reproduce: - Install `sale_mrp` and `l10n_ke_edi_oscu_stock` - Set company country to be 'Kenya' - Run the `test_kit_cogs_entry_with_delivery_line_removal` test > odoo.exceptions.UserError: Cannot create an invoice. No items are available to invoice. ### Cause of Issue: The test validates COGS entries for a kit by creating a sale order, then generating an invoice. When `l10n_ke_edi_oscu_stock` is installed, it overrides the `invoice_policy` of all storable products for Kenyan companies to `'delivery'`. https://github.com/odoo/enterprise/blob/82b736a283ed5ab3ad431a1cdbcedc1b8e3c2d7c/l10n_ke_edi_oscu_stock/models/product.py#L16-L21 Because the test removes a required component from the picking, the delivered quantity of the kit is computed as 0. Since the kit's invoice policy is dynamically forced to `'delivery'` by the localization, calling `_create_invoices()` raises a `UserError` as there are no delivered items to invoice, failing the test on runbot. ### Fix: Ensure that kit product use an invoicing policy of 'Ordered Quantities' rather than the default 'Delivered Quantities'. This allows the test to proceed and correctly evaluate the core COGS computation logic it was designed to check. runbot-243342 Forward-Port-Of: odoo/odoo#279450
**Description of the issue/feature this PR addresses:** When adding a product with an analytic distribution to a Sales Order that is already linked to a project, the product's analytic distribution is not automatically applied to the order line. This occurs due to a previous commit that attempted to protect manually entered analytic distributions from being overwritten when an SO is confirmed and a project is generated. To do this, the old code filtered out any non-empty project lines and
Original PR description
**Description of the issue/feature this PR addresses:** When adding a product with an analytic distribution to a Sales Order that is already linked to a project, the product's analytic distribution…
**Description of the issue/feature this PR addresses:** When adding a product with an analytic distribution to a Sales Order that is already linked to a project, the product's analytic distribution is not automatically applied to the order line. This occurs due to a previous commit that attempted to protect manually entered analytic distributions from being overwritten when an SO is confirmed and a project is generated. To do this, the old code filtered out any non-empty project lines and bypassed calling `super()` on them. Consequently, if a line already had an analytic distribution (such as inheriting the project's), the system would skip computing the product's specific distribution rules entirely. This commit resolves the issue by reverting that change, ensuring the base compute method is always called so product-based rules execute correctly. While this means manual analytic entries added before the compute trigger might be overwritten, there is no perfect solution to prevent losing both manual and product distributions. As concluded with the Product Owner in a similar PR for Purchase Orders, we prioritize keeping the product's automated distribution, as it is much harder to manually reconstruct after its removal. The corresponding test is also reverted to its original state to reflect this expected behavior. A small test is added to ensure that the analytic distribution results are unchanged when adding a project to the SO. opw-6279406 **Steps to Reproduce:** - Accounting > Configuration > Settings > Analytics > enable Analytic Accounting - Accounting > Configuration > Analytic Accounting > Analytic Distribution Models - Create a new model with any product (e.g. “Bolt”) and any Analytic Distribution (e.g. “Production”) - Create SO, enable “Analytic Distribution” in filters - Add any customer, add the above product (e.g. “Bolt”), save - Observe that the “Production” Analytic Distribution is automatically populated - On the same SO > Other Info> Project > add (e.g. “Home Construction”) - Then go back to Order Lines and remove the previous SOL and create a new one with the same product > save - Observe that the “Production” Analytic Distribution is not added (although “Home Construction” is) **Current behavior before PR:** - Product analytic distributions are not automatically applied when the Sales Order is already linked to a project **Desired behavior after PR is merged:** - Product analytic distributions are automatically applied even when the Sales Order is linked to a project **Note:** This commit basically ports a fix/revert (https://github.com/odoo/odoo/commit/54852978617cfb2d8c5afdcf80adbf6c0605093c) introduced to the project_purchase module for the same issue. Their commit message is quite detailed in explaining the issue. To quote: >However, due to the agency of the code, we cannot prevent losing *both* manually added analytic distributions and product analytic distribution. After consulting the product owner, we concluded that there was no perfect solution in this case, but we'd rather keep the product analytic distribution, as it is much harder to add it again after its removal. Therefore, this commit reverts the previously mentioned commit, while keeping the refactor it introduced. The referenced initial commit is here: https://github.com/odoo/odoo/commit/3dfa98bd3b9d5ababe3a7548d604e22350023799 Forward-Port-Of: odoo/odoo#274893
In this commit: - Center the preset card using grid positioning when only one preset is available to prevent it from spanning the full container width. Task:6217791
Original PR description
In this commit: - Center the preset card using grid positioning when only one preset is available to prevent it from spanning the full container width. Task:6217791
Issue: Outstanding credits/debits from a branch don't appear on the main company and inversely. Cause : From odoo/odoo#255875 outstanding credits/debits are limited by company to prevent different company issues on validation. However, this error is raised for `account.move` having different root companies. Which allow move from different branches of the same company. Steps to reproduce: - create a company and a branch - in the main company create a customer payment and valid it - in
Original PR description
Issue: Outstanding credits/debits from a branch don't appear on the main company and inversely. Cause : From odoo/odoo#255875 outstanding credits/debits are limited by company to prevent different company issues on validation. However, this error is raised for `account.move` having different root companies. Which allow move from different branches of the same company. Steps to reproduce: - create a company and a branch - in the main company create a customer payment and valid it - in the branch, create an invoice for the same customer and confirm it Current behavior: - the outstanding payment from the main company doesn't appear on the branch invoice, However, it's possible to reconcile it from the Journal entry view Expected behavior: - the outstanding payment from the main company appears on the branch invoice, opw-6140689 Forward-Port-Of: odoo/odoo#280018 Forward-Port-Of: odoo/odoo#262260
Steps to reproduce 1. Create two products and assign the same vendor to both in the Purchase tab 2. Create two Sales Orders using the dropship route (one product per order) 3. Generate and merge the corresponding Purchase Orders, then confirm the merged PO 4. Validate the dropship transfer Issue stock.picking.sale_id is a Many2one (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/sale_stock/models/stock.py#L99) computed from procurement.group.sale_id, an
Original PR description
Steps to reproduce 1. Create two products and assign the same vendor to both in the Purchase tab 2. Create two Sales Orders using the dropship route (one product per order) 3. Generate and merge the…
Steps to reproduce 1. Create two products and assign the same vendor to both in the Purchase tab 2. Create two Sales Orders using the dropship route (one product per order) 3. Generate and merge the corresponding Purchase Orders, then confirm the merged PO 4. Validate the dropship transfer Issue stock.picking.sale_id is a Many2one (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/sale_stock/models/stock.py#L99) computed from procurement.group.sale_id, and stock.picking.group_id is a stored related on move_ids.group_id (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/stock/models/stock_picking.py#L186). A single picking can therefore only resolve to one SO. _create_picking (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/purchase_stock/models/purchase_order.py#L290) builds one picking per PO and _prepare_stock_moves assigns every move the merged PO's group_id (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/purchase_stock/models/purchase_order_line.py#L307), so when a merged dropship PO carries lines from multiple SOs every move lands in one picking under the PO group. Only one SO gets linked and the others stay "not fully delivered" even after validation. Solution Override PurchaseOrderLine._prepare_stock_moves to set group_id to the SO's procurement_group_id when sale_line_id is set, so each dropship move is created in its originating SO's procurement group. Override PurchaseOrder._create_picking to detect dropship POs whose order lines span more than one SO and create one picking per SO group by calling _prepare_picking and _create_stock_moves per group. picking.group_id then resolves to the SO group via the stored related field, picking.sale_id points to the right SO, and delivery_status updates correctly on validation. opw-6094608 Forward-Port-Of: odoo/odoo#279843 Forward-Port-Of: odoo/odoo#257823
[*]=website 1. Sync background shape color with color preset. Steps to reproduce: 1. Go to the website and enter edit mode. 3. Drop any snippet. 4. Add a background shape. 5. Set the background shape color to "o-color-1". 6. Go to theme tab. 7. Change the value of theme color 1 from theme preset. Issue: The background shape color is not updated when the theme color changes. Reason: The background shape color is embedded in the
Original PR description
[*]=website 1. Sync background shape color with color preset. Steps to reproduce: 1. Go to the website and enter edit mode. 3. Drop any snippet. 4. Add a background shape. 5. Set the background shape…
[*]=website
1. Sync background shape color with color preset.
Steps to reproduce:
1. Go to the website and enter edit mode.
3. Drop any snippet.
4. Add a background shape.
5. Set the background shape color to "o-color-1".
6. Go to theme tab.
7. Change the value of theme color 1 from theme preset.
Issue:
The background shape color is not updated when the theme color changes.
Reason:
The background shape color is embedded in the URL of the "**background-image**" style attribute. When the theme color value changes, this URL is not updated. Additionally, the URL uses color variables rather than resolved hexadecimal color values as parameters. As a result, even when an updation occurs, the URL itself remains unchanged, preventing the background shape color from being updated.
2. Sync image shape color with color preset.
Steps to reproduce:
1. Go to the website and enter edit mode.
2. Drop any snippet.
4. Click on the image and add a shape.
5. Set the image shape color to "o-color-1".
6. Go to theme tab.
7. Change the value of theme color 1 from theme preset.
Issue:
The image shape color is not updated when the theme color changes.
Reason:
When the theme color value changes, the SVGs are not re-fetched. Additionally, the image "**shapeColors**" dataset stores the hexadecimal value of the theme color instead of the corresponding CSS variable. As a result, there is no way to determine which theme color was selected (for example, whether `o-color-1` or `o-color-2`), since only the hex value is available.
task-5438314
Forward-Port-Of: odoo/odoo#274079
Forward-Port-Of: odoo/odoo#241968**Description of the issue/feature this PR addresses:** `test_search_date_category` is failing across runbot builds Remove the blanket deletion of all repair orders at the start of test_search_date_category and replace the exact count assertion with assertIn. This avoids interfering with other test data and makes the test resilient to pre-existing records in the database. **Current behavior before PR:** ``` ERROR: TestRepair.test_search_date_category Traceback (most recent call last):
Original PR description
**Description of the issue/feature this PR addresses:** `test_search_date_category` is failing across runbot builds Remove the blanket deletion of all repair orders at the start of…
**Description of the issue/feature this PR addresses:**
`test_search_date_category` is failing across runbot builds
Remove the blanket deletion of all repair orders at the start of test_search_date_category and replace the exact count assertion with assertIn. This avoids interfering with other test data and makes the test resilient to pre-existing records in the database.
**Current behavior before PR:**
```
ERROR: TestRepair.test_search_date_category
Traceback (most recent call last):
File "/data/build/odoo/addons/repair/tests/test_repair.py", line 915, in test_search_date_category
self.env['repair.order'].search([]).unlink()
File "/data/build/odoo/addons/rating/models/mail_thread.py", line 21, in unlink
result = super().unlink()
^^^^^^^^^^^^^^^^
File "/data/build/odoo/addons/mail/models/mail_thread.py", line 391, in unlink
res = super(MailThread, self).unlink()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/build/odoo/addons/mail/models/models.py", line 46, in unlink
result = super().unlink()
^^^^^^^^^^^^^^^^
File "/data/build/odoo/odoo/orm/models.py", line 4131, in unlink
func(self)
File "/data/build/odoo/addons/repair/models/repair.py", line 421, in _unlink_except_confirmed
repairs_to_cancel.action_repair_cancel()
File "/data/build/enterprise/quality_repair/models/repair.py", line 114, in action_repair_cancel
res = super().action_repair_cancel()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/build/odoo/addons/repair/models/repair.py", line 475, in action_repair_cancel
raise UserError(_("You cannot cancel a Repair Order that's already been completed"))
odoo.exceptions.UserError: You cannot cancel a Repair Order that's already been completed
```
**Desired behavior after PR is merged:**
`test_search_date_category` passes
opw-[4998413](https://www.odoo.com/odoo/my-tasks/4998413)
runbot.build.error-[231146](https://runbot.odoo.com/odoo/runbot.build.error/231146)
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#267852owl 3 through an error when title returned as null instead of empty string task-6345714
Original PR description
owl 3 through an error when title returned as null instead of empty string task-6345714
**Steps to reproduce:** 1. Install Sales app and open any sale order 2. In the "Terms and conditions" text area at the bottom, apply the "/Switch direction" command for an empty block **Issue:** The feature doesn't work when you apply it on an empty line **Why this happens:** Before the fix, the switch-direction logic depended on selected text nodes, and effectively ignored empty content nodes. **Fix:** The problem has been fixed in 19.4 as an [IMP] in this commit 9c97fc464ffba5088
Original PR description
**Steps to reproduce:** 1. Install Sales app and open any sale order 2. In the "Terms and conditions" text area at the bottom, apply the "/Switch direction" command for an empty block **Issue:** The feature doesn't work when you apply it on an empty line **Why this happens:** Before the fix, the switch-direction logic depended on selected text nodes, and effectively ignored empty content nodes. **Fix:** The problem has been fixed in 19.4 as an [IMP] in this commit 9c97fc464ffba5088642d7699b3e033c1fcc2564, so this is essentially a backport for that fix. opw-6344750 Forward-Port-Of: odoo/odoo#279887 Forward-Port-Of: odoo/odoo#276536
…F fetch Nilvera PDF retrieval (the manual "Get PDF" action and the scheduled "retrieve sale PDFs" cron) hardcoded the "Sale" document category. That is correct for e-invoices (/einvoice/Sale/{uuid}/pdf) but wrong for e-archive documents, whose resource is "Invoices". For e-archive invoices it produced GET /earchive/Sale/{uuid}/pdf, which Nilvera answers with 404, surfacing to the user as "Odoo could not perform this action at the moment... Not Found - 404" and making the cron raise on every
Original PR description
…F fetch
Nilvera PDF retrieval (the manual "Get PDF" action and the scheduled "retrieve sale PDFs" cron) hardcoded the "Sale" document category. That is correct for e-invoices (/einvoice/Sale/{uuid}/pdf) but wrong for e-archive documents, whose resource is "Invoices". For e-archive invoices it produced GET /earchive/Sale/{uuid}/pdf, which Nilvera answers with 404, surfacing to the user as "Odoo could not perform this action at the moment... Not Found - 404" and making the cron raise on every run.
Derive the document category from the invoice channel so e-archive resolves to /earchive/invoices/{uuid}/pdf while e-invoice keeps using /einvoice/sale/{uuid}/pdf.
OPW-6311661
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#278796Purpose of this PR: - On double click, opening the toolbar is delayed by 300ms to prevent flickering before a potential triple click. - However, mouseup was re-enabling selection tracking (onSelectionChangeActive = true) before the 300ms delay finished. Because browser selectionchange events are dispatched asynchronously after mouseup, they triggered updateToolbar() immediately, bypassing the 300ms delay. - This fix re-enables selection tracking only after the 300ms debounced update actuall
Original PR description
Purpose of this PR: - On double click, opening the toolbar is delayed by 300ms to prevent flickering before a potential triple click. - However, mouseup was re-enabling selection tracking (onSelectionChangeActive = true) before the 300ms delay finished. Because browser selectionchange events are dispatched asynchronously after mouseup, they triggered updateToolbar() immediately, bypassing the 300ms delay. - This fix re-enables selection tracking only after the 300ms debounced update actually finishes. runbot-941543 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279826 Forward-Port-Of: odoo/odoo#278025
Before this commit, the user's presence was not sent to the server when another device reported this user as away/offline while this device was online. `ImStatusMixin` reacts to `presence_status` and correct the user's presence on the server when needed (e.g. locally online while away was received). Since [1], the check on the presence being the one of the current user is wrong (comparing `store.self` to the presence user record). The tests only pass because of the initial presence upda
Original PR description
Before this commit, the user's presence was not sent to the server when another device reported this user as away/offline while this device was online. `ImStatusMixin` reacts to `presence_status` and correct the user's presence on the server when needed (e.g. locally online while away was received). Since [1], the check on the presence being the one of the current user is wrong (comparing `store.self` to the presence user record). The tests only pass because of the initial presence update. This commit fixes the issue and ensures the initial update is not confused by the correction. [1]: https://github.com/odoo/odoo/pull/248168 runbot-944282 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
### Steps to reproduce: - Open CRM app (or any model with chatter) - Open any record (e.g., an Opportunity) - Click "Log note" - Type some text into the input box - Click the "Full composer" icon to open the mail composition wizard - Log the note - Click "Log Note" again > The note is logged successfully, but the text remains visible inside the small inline chatter input box as if it was never sent. (Doesn't happen everytime) ### Cause of Issue: Composer drafts are auto-saved to I
Original PR description
### Steps to reproduce: - Open CRM app (or any model with chatter) - Open any record (e.g., an Opportunity) - Click "Log note" - Type some text into the input box - Click the "Full composer" icon to…
### Steps to reproduce: - Open CRM app (or any model with chatter) - Open any record (e.g., an Opportunity) - Click "Log note" - Type some text into the input box - Click the "Full composer" icon to open the mail composition wizard - Log the note - Click "Log Note" again > The note is logged successfully, but the text remains visible inside the small inline chatter input box as if it was never sent. (Doesn't happen everytime) ### Cause of Issue: Composer drafts are auto-saved to IndexedDB via the debounced saveContent() https://github.com/odoo/odoo/blob/ac2d15c1132af16f00f8955d1be9b43a8626d9bd/addons/mail/static/src/core/common/composer.js#L986-L1003 `clear()`, called from the Full Composer's `onClose` handler after logging a note, only resets in-memory composer state and removes a `localStorage` key — it never deletes the corresponding `IndexedDB` entry. ### Fix: Have `clear()` also delete the persisted IndexedDB draft via the helper used after a normal chatter post in `_sendMessage()`, so `clear()` fully tears down both in-memory and persisted state. opw-6354149
When an order from a closed session is invoiced, a misc reversal move is created to "extract" the order from the session closing entry. When the PoS config uses a currency different from the company currency, posting that reversal move could fail with "The entry is not balanced.", making it impossible to invoice the order. Steps to reproduce: - company in currency A, PoS config in currency B, with a conversion rate producing rounding drift (e.g. 0.4007) - sell a product of 20.0 B + 15% t
Original PR description
When an order from a closed session is invoiced, a misc reversal move is created to "extract" the order from the session closing entry. When the PoS config uses a currency different from the company…
When an order from a closed session is invoiced, a misc reversal move is created to "extract" the order from the session closing entry. When the PoS config uses a currency different from the company currency, posting that reversal move could fail with "The entry is not balanced.", making it impossible to invoice the order. Steps to reproduce: - company in currency A, PoS config in currency B, with a conversion rate producing rounding drift (e.g. 0.4007) - sell a product of 20.0 B + 15% tax (23.0 B), paid by bank, without invoicing - close the session - set a partner on the order and invoice it => UserError: "The entry is not balanced." Cause: in `_prepare_aml_values_list_per_nature`, the product and tax lines each get their balance converted and rounded individually (20.0 * 0.4007 -> 8.01, 3.0 * 0.4007 -> 1.20), while the payment term line was converted from the payment total, without rounding (23.0 * 0.4007 -> 9.2161). Per-line rounding does not distribute over the sum, so the balances could differ by a few cents (8.01 + 1.20 != 9.22) and the move could not be posted. The closing entry has the balancing-account wizard as an escape valve for such differences; the reversal move had none. Fix, following what is done for regular invoices (see `account.move._compute_needed_terms`, where the payment term balance is derived from the sum of the already rounded lines): - round the payment term conversions - put the conversion residual on the last payment term line so the payment terms exactly counterbalance the other lines, but only when the amounts in currency are balanced, so it can only absorb rounding drift - include the cash rounding amounts in the accumulated totals - fix the swapped `amount_currency`/`balance` values when merging two non-split payments on the same receivable account opw-6375309 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275673
Miscellaneous changes
### Batch per all moves, not per product **Problem:** In https://github.com/odoo/odoo/pull/250526, moves are batched in order to prevent memory error in databases with many stock.move. However, the batching is done on the moves per product, meaning batches can be very small relative to the limit, and this causes unecessary queries compared to batching per all moves to process. **Solution:** Iterate through all moves rather than per product, and use/save the per product results direct
Original PR description
### Batch per all moves, not per product **Problem:** In https://github.com/odoo/odoo/pull/250526, moves are batched in order to prevent memory error in databases with many stock.move. However, the…
### Batch per all moves, not per product **Problem:** In https://github.com/odoo/odoo/pull/250526, moves are batched in order to prevent memory error in databases with many stock.move. However, the batching is done on the moves per product, meaning batches can be very small relative to the limit, and this causes unecessary queries compared to batching per all moves to process. **Solution:** Iterate through all moves rather than per product, and use/save the per product results directly in the relevant dicts. --- ### Batch and prefetch for initial product std_price **Problem:** When initializing products' standard price before replaying valuation, the first stock.move is read. This happens before any prefetching or batching occurs, so a query is made per move and contributes to performance issues. **Solution:** Batch and prefetch the products' first moves, then initialize the standard price. --- ### Use cached is_in and is_out values **Problem:** In `_get_valued_qty()`, `_is_in()` and `_is_out()` are called for each move, but these methods are already called for these moves and cached as `is_in` and `is_out`. **Solution:** Replace the method calls with the cached fields. If the move is not done, we fallback to the methods as the cached fields will be false for not done moves. --- **Perf Tables:** Record: product.template, each with AVCO automated valuation and a done in move Today: |Record count|Time before|Queries before|Time after|Queries after| |------------|-----------|--------------|----------|-------------| |1k |1.08s |264 |697ms |235 | |5k |2.74s |864 |2.23s |864 | |10k |4.83s |1375 |4.56s |1870 | At Date: |Record count|Time before|Queries before|Time after|Queries after| |------------|-----------|--------------|----------|-------------| |1k |3.10s |6109 |925ms |386 | |5k |14.68s |30299 |3.50s |1564 | |10k |26.98s |59173 |7.16s |3590 | opw-6134244 Forward-Port-Of: odoo/odoo#261624
Simplified version of https://github.com/odoo/odoo/pull/276689 Forward-Port-Of: odoo/odoo#277083 Forward-Port-Of: odoo/odoo#276696
Original PR description
Simplified version of https://github.com/odoo/odoo/pull/276689 Forward-Port-Of: odoo/odoo#277083 Forward-Port-Of: odoo/odoo#276696
This is in preparation for forcefully recommending the use of `execute_query` and `SQL` as early as 19.0. While `execute_query` is the primary recommendation, `execute(SQL(...))` is an OK alternative, but static checking limitations mean queries constructed in function calls, or callers (that includes the implementation of `execute_query` itself), or using conditionals, will be flagged. In that case the easiest pattern is execute(SQL("%s", query)) which we do not want to penalize overl
Original PR description
This is in preparation for forcefully recommending the use of `execute_query` and `SQL` as early as 19.0. While `execute_query` is the primary recommendation, `execute(SQL(...))` is an OK alternative, but static checking limitations mean queries constructed in function calls, or callers (that includes the implementation of `execute_query` itself), or using conditionals, will be flagged. In that case the easiest pattern is
execute(SQL("%s", query))
which we do not want to penalize overly.
- Add fast path for `SQL("%s", arg: SQL)`.
- Improve fast-path for `SQL(SQL())` to do ~nothing when possible.
- Allow overriding `to_flush` in both case, fix site which needs that
- Update type dispatches to check for `Iterable` instead of `__iter__`. this both helps type checkers and is actually correct.
Forward-Port-Of: odoo/odoo#280108
Forward-Port-Of: odoo/odoo#25893014 changes
Enhancements to existing features
Currently, Peppol product detection relies strictly on barcode or default_code matching, which fails when vendors use their own codes. Accurate product identification is essential before running the predictive model (for taxes/accounts) and is a strict prerequisite for Purchase Orders matching to function correctly. This PR makes the product matching relies on the Vendor Product Code as the first priority ( SellersItemIdentification or StandardItemIdentification or BuyersItemIdentification
Original PR description
Currently, Peppol product detection relies strictly on barcode or default_code matching, which fails when vendors use their own codes. Accurate product identification is essential before running the predictive model (for taxes/accounts) and is a strict prerequisite for Purchase Orders matching to function correctly. This PR makes the product matching relies on the Vendor Product Code as the first priority ( SellersItemIdentification or StandardItemIdentification or BuyersItemIdentification ) task-6171251 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262801
Forward-Port-Of: odoo/odoo#278655
Original PR description
Forward-Port-Of: odoo/odoo#278655
Resolved issues and error corrections
'_getEmptyOrder' could reuse an order whose background sync was still processing; the stale sync response then wiped is_refund and detached the refund line. We now skip orders currently in `syncingOrders` when picking the refund destination so the refund always lands on a clean order and syncs fresh. runbot error : 242604
Original PR description
'_getEmptyOrder' could reuse an order whose background sync was still processing; the stale sync response then wiped is_refund and detached the refund line. We now skip orders currently in `syncingOrders` when picking the refund destination so the refund always lands on a clean order and syncs fresh. runbot error : 242604
*:mrp_subcontracting_purchase Issue before this commit: ======================== - In inter-warehouse transfers with `multi-step delivery` and in multi-step manufacturing flows, demand moves were not correctly counted in the monthly demand. - Also, direct transfers to customer and subcontracting locations generated from `orderpoint` were also not counted correctly (when checked before move scheduled on the same day). This resulted in lower monthly demand values than the actual demand and
Original PR description
*:mrp_subcontracting_purchase Issue before this commit: ======================== - In inter-warehouse transfers with `multi-step delivery` and in multi-step manufacturing flows, demand moves were not…
*:mrp_subcontracting_purchase Issue before this commit: ======================== - In inter-warehouse transfers with `multi-step delivery` and in multi-step manufacturing flows, demand moves were not correctly counted in the monthly demand. - Also, direct transfers to customer and subcontracting locations generated from `orderpoint` were also not counted correctly (when checked before move scheduled on the same day). This resulted in lower monthly demand values than the actual demand and could lead to inaccurate purchase planning. Steps to Reproduce: ========================= - Install `purchase_stock` module and enable multi-step routes. - Set the Outgoing Shipments in the warehouse to 2-step/3-step. - Create a second warehouse and configure it to `resupply from another warehouse`. - Create a storable product and assign a vendor. - Create an orderpoint for the product in the second warehouse, set the route to the warehouse resupply route, and trigger the replenishment. - Go to Purchase → Create RFQ for the vendor and open the catalog. Observation: The replenishment transfer demand is not correctly counted in the monthly demand Cause of the issue: ========================= - In [PR](https://github.com/odoo/odoo/pull/244180), the monthly demand move domain was updated to filter out intermediate customer delivery moves using `move_dest_ids.origin_returned_move_id`. However, inter-warehouse replenishment delivery moves also have `move_dest_ids` linked to receipt moves of the other warehouse, but `origin_returned_move_id is not set` since they are not return move Because of this, these valid demand moves were incorrectly excluded from the monthly demand computation. - Also, in inter-warehouse flows with multi-step delivery, `delivery moves` stay in the `waiting state` since they wait for another operation, so they were also not counted. Additionally, `orderpoint-triggered` moves use a `fixed midday scheduled time`, and since monthly demand was computed using the current timestamp as the limit date, same-day moves could be excluded if checked before midday. After This Commit: ========================= - The monthly demand move domain was updated to correctly count inter-warehouse, manufacturing, and subcontracting resupply demand moves while still avoiding inflated demand from intermediate moves. The move state domain was also updated to `include waiting moves` in multi-step flows, and the limit date now uses the full current day so same day moves are counted correctly. Enterprise PR: odoo/enterprise#115944 TaskID-5490137 Forward-Port-Of: odoo/odoo#279853 Forward-Port-Of: odoo/odoo#262435
When running `ŧest_free_reservation`, it could happen on very rare occasions that both moves would be created at a different second. In such cases, the test would fail. Since we want to test the case with *exact* same dates, we can't use `assertAlmostEqual` which is usually better for dates. Instead, we freeze the time for the duration of the creation / assignation. runbot-944453 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of:
Original PR description
When running `ŧest_free_reservation`, it could happen on very rare occasions that both moves would be created at a different second. In such cases, the test would fail. Since we want to test the case with *exact* same dates, we can't use `assertAlmostEqual` which is usually better for dates. Instead, we freeze the time for the duration of the creation / assignation. runbot-944453 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279565 Forward-Port-Of: odoo/odoo#278103
Before this commit, when a product had a multi choice attribute with only one option, it was not possible to configure the product in the POS or in the self. This is a problem since multi choice are different from other attribute display type because their options are opttional. The user should thus be able to select if he wants the option or not so we should display the configurator even if there is only one option. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.
Original PR description
Before this commit, when a product had a multi choice attribute with only one option, it was not possible to configure the product in the POS or in the self. This is a problem since multi choice are different from other attribute display type because their options are opttional. The user should thus be able to select if he wants the option or not so we should display the configurator even if there is only one option. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#271287
**Description of the issue/feature this PR addresses:** When adding a product with an analytic distribution to a Sales Order that is already linked to a project, the product's analytic distribution is not automatically applied to the order line. This occurs due to a previous commit that attempted to protect manually entered analytic distributions from being overwritten when an SO is confirmed and a project is generated. To do this, the old code filtered out any non-empty project lines and
Original PR description
**Description of the issue/feature this PR addresses:** When adding a product with an analytic distribution to a Sales Order that is already linked to a project, the product's analytic distribution…
**Description of the issue/feature this PR addresses:** When adding a product with an analytic distribution to a Sales Order that is already linked to a project, the product's analytic distribution is not automatically applied to the order line. This occurs due to a previous commit that attempted to protect manually entered analytic distributions from being overwritten when an SO is confirmed and a project is generated. To do this, the old code filtered out any non-empty project lines and bypassed calling `super()` on them. Consequently, if a line already had an analytic distribution (such as inheriting the project's), the system would skip computing the product's specific distribution rules entirely. This commit resolves the issue by reverting that change, ensuring the base compute method is always called so product-based rules execute correctly. While this means manual analytic entries added before the compute trigger might be overwritten, there is no perfect solution to prevent losing both manual and product distributions. As concluded with the Product Owner in a similar PR for Purchase Orders, we prioritize keeping the product's automated distribution, as it is much harder to manually reconstruct after its removal. The corresponding test is also reverted to its original state to reflect this expected behavior. A small test is added to ensure that the analytic distribution results are unchanged when adding a project to the SO. opw-6279406 **Steps to Reproduce:** - Accounting > Configuration > Settings > Analytics > enable Analytic Accounting - Accounting > Configuration > Analytic Accounting > Analytic Distribution Models - Create a new model with any product (e.g. “Bolt”) and any Analytic Distribution (e.g. “Production”) - Create SO, enable “Analytic Distribution” in filters - Add any customer, add the above product (e.g. “Bolt”), save - Observe that the “Production” Analytic Distribution is automatically populated - On the same SO > Other Info> Project > add (e.g. “Home Construction”) - Then go back to Order Lines and remove the previous SOL and create a new one with the same product > save - Observe that the “Production” Analytic Distribution is not added (although “Home Construction” is) **Current behavior before PR:** - Product analytic distributions are not automatically applied when the Sales Order is already linked to a project **Desired behavior after PR is merged:** - Product analytic distributions are automatically applied even when the Sales Order is linked to a project **Note:** This commit basically ports a fix/revert (https://github.com/odoo/odoo/commit/54852978617cfb2d8c5afdcf80adbf6c0605093c) introduced to the project_purchase module for the same issue. Their commit message is quite detailed in explaining the issue. To quote: >However, due to the agency of the code, we cannot prevent losing *both* manually added analytic distributions and product analytic distribution. After consulting the product owner, we concluded that there was no perfect solution in this case, but we'd rather keep the product analytic distribution, as it is much harder to add it again after its removal. Therefore, this commit reverts the previously mentioned commit, while keeping the refactor it introduced. The referenced initial commit is here: https://github.com/odoo/odoo/commit/3dfa98bd3b9d5ababe3a7548d604e22350023799 Forward-Port-Of: odoo/odoo#274893
This commit fix the regex used in `street_split` to be more complient. Before: address format was "street_name street_number - street_number2" Now, street_number can be in front of street_name. Format is also less strict, allowing multiple numbers in the street_name without skipping the building number. Linked: https://github.com/odoo/enterprise/pull/121674 task-6317758 Forward-Port-Of: odoo/odoo#279934 Forward-Port-Of: odoo/odoo#271855
Original PR description
This commit fix the regex used in `street_split` to be more complient. Before: address format was "street_name street_number - street_number2" Now, street_number can be in front of street_name. Format is also less strict, allowing multiple numbers in the street_name without skipping the building number. Linked: https://github.com/odoo/enterprise/pull/121674 task-6317758 Forward-Port-Of: odoo/odoo#279934 Forward-Port-Of: odoo/odoo#271855
Restore the previous behavior by calling `checkAccessRight()` without awaiting it during `PosStore.setup()`. This prevents the POS startup from being blocked while the access check is running. This fixes PoS startup and offline fallback tours timing out while waiting for the "Continue with limited functionality" dialog. Runbot Error-[944421](https://runbot.odoo.com/odoo/error/944421) Forward-Port-Of: odoo/odoo#279792 Forward-Port-Of: odoo/odoo#278628
Original PR description
Restore the previous behavior by calling `checkAccessRight()` without awaiting it during `PosStore.setup()`. This prevents the POS startup from being blocked while the access check is running. This fixes PoS startup and offline fallback tours timing out while waiting for the "Continue with limited functionality" dialog. Runbot Error-[944421](https://runbot.odoo.com/odoo/error/944421) Forward-Port-Of: odoo/odoo#279792 Forward-Port-Of: odoo/odoo#278628
Use "VAT" instead of "TAX" for the default UK tax groups. Also set "Subtotal" as their preceding subtotal label so that it replaces "Untaxed Amount". task-[6413495](https://www.odoo.com/odoo/project/967/tasks/6413495) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279865 Forward-Port-Of: odoo/odoo#278351
Original PR description
Use "VAT" instead of "TAX" for the default UK tax groups. Also set "Subtotal" as their preceding subtotal label so that it replaces "Untaxed Amount". task-[6413495](https://www.odoo.com/odoo/project/967/tasks/6413495) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279865 Forward-Port-Of: odoo/odoo#278351
Steps to reproduce 1. Create two products and assign the same vendor to both in the Purchase tab 2. Create two Sales Orders using the dropship route (one product per order) 3. Generate and merge the corresponding Purchase Orders, then confirm the merged PO 4. Validate the dropship transfer Issue stock.picking.sale_id is a Many2one (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/sale_stock/models/stock.py#L99) computed from procurement.group.sale_id, an
Original PR description
Steps to reproduce 1. Create two products and assign the same vendor to both in the Purchase tab 2. Create two Sales Orders using the dropship route (one product per order) 3. Generate and merge the…
Steps to reproduce 1. Create two products and assign the same vendor to both in the Purchase tab 2. Create two Sales Orders using the dropship route (one product per order) 3. Generate and merge the corresponding Purchase Orders, then confirm the merged PO 4. Validate the dropship transfer Issue stock.picking.sale_id is a Many2one (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/sale_stock/models/stock.py#L99) computed from procurement.group.sale_id, and stock.picking.group_id is a stored related on move_ids.group_id (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/stock/models/stock_picking.py#L186). A single picking can therefore only resolve to one SO. _create_picking (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/purchase_stock/models/purchase_order.py#L290) builds one picking per PO and _prepare_stock_moves assigns every move the merged PO's group_id (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/purchase_stock/models/purchase_order_line.py#L307), so when a merged dropship PO carries lines from multiple SOs every move lands in one picking under the PO group. Only one SO gets linked and the others stay "not fully delivered" even after validation. Solution Override PurchaseOrderLine._prepare_stock_moves to set group_id to the SO's procurement_group_id when sale_line_id is set, so each dropship move is created in its originating SO's procurement group. Override PurchaseOrder._create_picking to detect dropship POs whose order lines span more than one SO and create one picking per SO group by calling _prepare_picking and _create_stock_moves per group. picking.group_id then resolves to the SO group via the stored related field, picking.sale_id points to the right SO, and delivery_status updates correctly on validation. opw-6094608 Forward-Port-Of: odoo/odoo#279843 Forward-Port-Of: odoo/odoo#257823
**Description of the issue/feature this PR addresses:** `test_search_date_category` is failing across runbot builds Remove the blanket deletion of all repair orders at the start of test_search_date_category and replace the exact count assertion with assertIn. This avoids interfering with other test data and makes the test resilient to pre-existing records in the database. **Current behavior before PR:** ``` ERROR: TestRepair.test_search_date_category Traceback (most recent call last):
Original PR description
**Description of the issue/feature this PR addresses:** `test_search_date_category` is failing across runbot builds Remove the blanket deletion of all repair orders at the start of…
**Description of the issue/feature this PR addresses:**
`test_search_date_category` is failing across runbot builds
Remove the blanket deletion of all repair orders at the start of test_search_date_category and replace the exact count assertion with assertIn. This avoids interfering with other test data and makes the test resilient to pre-existing records in the database.
**Current behavior before PR:**
```
ERROR: TestRepair.test_search_date_category
Traceback (most recent call last):
File "/data/build/odoo/addons/repair/tests/test_repair.py", line 915, in test_search_date_category
self.env['repair.order'].search([]).unlink()
File "/data/build/odoo/addons/rating/models/mail_thread.py", line 21, in unlink
result = super().unlink()
^^^^^^^^^^^^^^^^
File "/data/build/odoo/addons/mail/models/mail_thread.py", line 391, in unlink
res = super(MailThread, self).unlink()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/build/odoo/addons/mail/models/models.py", line 46, in unlink
result = super().unlink()
^^^^^^^^^^^^^^^^
File "/data/build/odoo/odoo/orm/models.py", line 4131, in unlink
func(self)
File "/data/build/odoo/addons/repair/models/repair.py", line 421, in _unlink_except_confirmed
repairs_to_cancel.action_repair_cancel()
File "/data/build/enterprise/quality_repair/models/repair.py", line 114, in action_repair_cancel
res = super().action_repair_cancel()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/build/odoo/addons/repair/models/repair.py", line 475, in action_repair_cancel
raise UserError(_("You cannot cancel a Repair Order that's already been completed"))
odoo.exceptions.UserError: You cannot cancel a Repair Order that's already been completed
```
**Desired behavior after PR is merged:**
`test_search_date_category` passes
opw-[4998413](https://www.odoo.com/odoo/my-tasks/4998413)
runbot.build.error-[231146](https://runbot.odoo.com/odoo/runbot.build.error/231146)
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#267852…F fetch Nilvera PDF retrieval (the manual "Get PDF" action and the scheduled "retrieve sale PDFs" cron) hardcoded the "Sale" document category. That is correct for e-invoices (/einvoice/Sale/{uuid}/pdf) but wrong for e-archive documents, whose resource is "Invoices". For e-archive invoices it produced GET /earchive/Sale/{uuid}/pdf, which Nilvera answers with 404, surfacing to the user as "Odoo could not perform this action at the moment... Not Found - 404" and making the cron raise on every
Original PR description
…F fetch
Nilvera PDF retrieval (the manual "Get PDF" action and the scheduled "retrieve sale PDFs" cron) hardcoded the "Sale" document category. That is correct for e-invoices (/einvoice/Sale/{uuid}/pdf) but wrong for e-archive documents, whose resource is "Invoices". For e-archive invoices it produced GET /earchive/Sale/{uuid}/pdf, which Nilvera answers with 404, surfacing to the user as "Odoo could not perform this action at the moment... Not Found - 404" and making the cron raise on every run.
Derive the document category from the invoice channel so e-archive resolves to /earchive/invoices/{uuid}/pdf while e-invoice keeps using /einvoice/sale/{uuid}/pdf.
OPW-6311661
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#278796Miscellaneous changes
The field `website_description` is empty for many partners (or empty html `<p><br></p>`). But for real partners published on the website, it can be huge, including base64 images. With this commit, we avoid prefetching the field when manipulating partners. It can lead to memory errors when looking for parnters on the website, where they all have (possibly heavy) values for this field. It's only really needed when displaying a single partner. --- I confirm I have signed the CLA and read
Original PR description
The field `website_description` is empty for many partners (or empty html `<p><br></p>`). But for real partners published on the website, it can be huge, including base64 images. With this commit, we avoid prefetching the field when manipulating partners. It can lead to memory errors when looking for parnters on the website, where they all have (possibly heavy) values for this field. It's only really needed when displaying a single partner. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
12 changes
Enhancements to existing features
Currently all of our iot boxes are updated on mondays. This PR adds the dynamic selection of the update day of the week based on the rpi serial number. This allows our iot boxes not to be updated all at the same time, reducing the risk of introducing bugs for our clients all at the same time. Related: https://github.com/odoo/odoo/pull/278914
Original PR description
Currently all of our iot boxes are updated on mondays. This PR adds the dynamic selection of the update day of the week based on the rpi serial number. This allows our iot boxes not to be updated all at the same time, reducing the risk of introducing bugs for our clients all at the same time. Related: https://github.com/odoo/odoo/pull/278914
Forward-Port-Of: odoo/odoo#278655
Original PR description
Forward-Port-Of: odoo/odoo#278655
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 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. closes odoo/odoo#276581 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#278236
Resolved issues and error corrections
The test for `hr_leave_attendance_report` failed Runbot's faketime tests for two reasons: * The report's view use SQL's reserved syntax `CURRENT_DATE` which always resolves to real system clock, and ignores Odoo's faketime mechanism. * The three tests used hardcoded dates. Since the report is exclusively concerned with the window of last 13 months. Faking the time in a future date further than this led to wrong results. This commit fixes both issues by: 1. Using `now()::date`
Original PR description
The test for `hr_leave_attendance_report` failed Runbot's faketime tests for two reasons: * The report's view use SQL's reserved syntax `CURRENT_DATE` which always resolves to real system clock, and ignores Odoo's faketime mechanism. * The three tests used hardcoded dates. Since the report is exclusively concerned with the window of last 13 months. Faking the time in a future date further than this led to wrong results. This commit fixes both issues by: 1. Using `now()::date` in the view instead of `CURRENT_DATE`. 2. Replacing the hardcoded dates in the tests by dates computed relative to `fields.Date.today()`. Runbot Errors: [1](https://runbot.odoo.com/odoo/runbot.build.error/944585), [2](https://runbot.odoo.com/odoo/runbot.build.error/944585/runbot.build.error/runbot.build.error/944584) Forward-Port-Of: odoo/odoo#279337
Steps to reproduce 1. Create two products and assign the same vendor to both in the Purchase tab 2. Create two Sales Orders using the dropship route (one product per order) 3. Generate and merge the corresponding Purchase Orders, then confirm the merged PO 4. Validate the dropship transfer Issue stock.picking.sale_id is a Many2one (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/sale_stock/models/stock.py#L99) computed from procurement.group.sale_id, an
Original PR description
Steps to reproduce 1. Create two products and assign the same vendor to both in the Purchase tab 2. Create two Sales Orders using the dropship route (one product per order) 3. Generate and merge the…
Steps to reproduce 1. Create two products and assign the same vendor to both in the Purchase tab 2. Create two Sales Orders using the dropship route (one product per order) 3. Generate and merge the corresponding Purchase Orders, then confirm the merged PO 4. Validate the dropship transfer Issue stock.picking.sale_id is a Many2one (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/sale_stock/models/stock.py#L99) computed from procurement.group.sale_id, and stock.picking.group_id is a stored related on move_ids.group_id (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/stock/models/stock_picking.py#L186). A single picking can therefore only resolve to one SO. _create_picking (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/purchase_stock/models/purchase_order.py#L290) builds one picking per PO and _prepare_stock_moves assigns every move the merged PO's group_id (https://github.com/odoo/odoo/blob/18c3a034b7d3772baca62d8d86efba2ca15f17b0/addons/purchase_stock/models/purchase_order_line.py#L307), so when a merged dropship PO carries lines from multiple SOs every move lands in one picking under the PO group. Only one SO gets linked and the others stay "not fully delivered" even after validation. Solution Override PurchaseOrderLine._prepare_stock_moves to set group_id to the SO's procurement_group_id when sale_line_id is set, so each dropship move is created in its originating SO's procurement group. Override PurchaseOrder._create_picking to detect dropship POs whose order lines span more than one SO and create one picking per SO group by calling _prepare_picking and _create_stock_moves per group. picking.group_id then resolves to the SO group via the stored related field, picking.sale_id points to the right SO, and delivery_status updates correctly on validation. opw-6094608 Forward-Port-Of: odoo/odoo#279843 Forward-Port-Of: odoo/odoo#257823
**Description of the issue/feature this PR addresses:** `test_search_date_category` is failing across runbot builds Remove the blanket deletion of all repair orders at the start of test_search_date_category and replace the exact count assertion with assertIn. This avoids interfering with other test data and makes the test resilient to pre-existing records in the database. **Current behavior before PR:** ``` ERROR: TestRepair.test_search_date_category Traceback (most recent call last):
Original PR description
**Description of the issue/feature this PR addresses:** `test_search_date_category` is failing across runbot builds Remove the blanket deletion of all repair orders at the start of…
**Description of the issue/feature this PR addresses:**
`test_search_date_category` is failing across runbot builds
Remove the blanket deletion of all repair orders at the start of test_search_date_category and replace the exact count assertion with assertIn. This avoids interfering with other test data and makes the test resilient to pre-existing records in the database.
**Current behavior before PR:**
```
ERROR: TestRepair.test_search_date_category
Traceback (most recent call last):
File "/data/build/odoo/addons/repair/tests/test_repair.py", line 915, in test_search_date_category
self.env['repair.order'].search([]).unlink()
File "/data/build/odoo/addons/rating/models/mail_thread.py", line 21, in unlink
result = super().unlink()
^^^^^^^^^^^^^^^^
File "/data/build/odoo/addons/mail/models/mail_thread.py", line 391, in unlink
res = super(MailThread, self).unlink()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/build/odoo/addons/mail/models/models.py", line 46, in unlink
result = super().unlink()
^^^^^^^^^^^^^^^^
File "/data/build/odoo/odoo/orm/models.py", line 4131, in unlink
func(self)
File "/data/build/odoo/addons/repair/models/repair.py", line 421, in _unlink_except_confirmed
repairs_to_cancel.action_repair_cancel()
File "/data/build/enterprise/quality_repair/models/repair.py", line 114, in action_repair_cancel
res = super().action_repair_cancel()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/data/build/odoo/addons/repair/models/repair.py", line 475, in action_repair_cancel
raise UserError(_("You cannot cancel a Repair Order that's already been completed"))
odoo.exceptions.UserError: You cannot cancel a Repair Order that's already been completed
```
**Desired behavior after PR is merged:**
`test_search_date_category` passes
opw-[4998413](https://www.odoo.com/odoo/my-tasks/4998413)
runbot.build.error-[231146](https://runbot.odoo.com/odoo/runbot.build.error/231146)
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#267852**Steps to reproduce:** 1. Install Sales app and open any sale order 2. In the "Terms and conditions" text area at the bottom, apply the "/Switch direction" command for an empty block **Issue:** The feature doesn't work when you apply it on an empty line **Why this happens:** Before the fix, the switch-direction logic depended on selected text nodes, and effectively ignored empty content nodes. **Fix:** The problem has been fixed in 19.4 as an [IMP] in this commit 9c97fc464ffba5088
Original PR description
**Steps to reproduce:** 1. Install Sales app and open any sale order 2. In the "Terms and conditions" text area at the bottom, apply the "/Switch direction" command for an empty block **Issue:** The feature doesn't work when you apply it on an empty line **Why this happens:** Before the fix, the switch-direction logic depended on selected text nodes, and effectively ignored empty content nodes. **Fix:** The problem has been fixed in 19.4 as an [IMP] in this commit 9c97fc464ffba5088642d7699b3e033c1fcc2564, so this is essentially a backport for that fix. opw-6344750 Forward-Port-Of: odoo/odoo#279887 Forward-Port-Of: odoo/odoo#276536
Ensure combo prices are computed in the backend. Forward-Port-Of: odoo/odoo#279652
Original PR description
Ensure combo prices are computed in the backend. Forward-Port-Of: odoo/odoo#279652
Purpose of this PR: - On double click, opening the toolbar is delayed by 300ms to prevent flickering before a potential triple click. - However, mouseup was re-enabling selection tracking (onSelectionChangeActive = true) before the 300ms delay finished. Because browser selectionchange events are dispatched asynchronously after mouseup, they triggered updateToolbar() immediately, bypassing the 300ms delay. - This fix re-enables selection tracking only after the 300ms debounced update actuall
Original PR description
Purpose of this PR: - On double click, opening the toolbar is delayed by 300ms to prevent flickering before a potential triple click. - However, mouseup was re-enabling selection tracking (onSelectionChangeActive = true) before the 300ms delay finished. Because browser selectionchange events are dispatched asynchronously after mouseup, they triggered updateToolbar() immediately, bypassing the 300ms delay. - This fix re-enables selection tracking only after the 300ms debounced update actually finishes. runbot-941543 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279826 Forward-Port-Of: odoo/odoo#278025
Steps to reproduce: 1. Install Calendar 2. Create a meeting in Calendar in form view 3. Set the video link on it 4. Turn on the debug mode 5. Now, clear the video link Issue: - Traceback ``` Uncaught Promise > Invalid props for component 'CopyButton': 'content' is not a string or object or function ``` Cause: - The 'CopyButton' component expect content to be a string, object or function but receives false. It does not happen in previous versions because in the refector https:/
Original PR description
Steps to reproduce: 1. Install Calendar 2. Create a meeting in Calendar in form view 3. Set the video link on it 4. Turn on the debug mode 5. Now, clear the video link Issue: - Traceback ``` Uncaught…
Steps to reproduce: 1. Install Calendar 2. Create a meeting in Calendar in form view 3. Set the video link on it 4. Turn on the debug mode 5. Now, clear the video link Issue: - Traceback ``` Uncaught Promise > Invalid props for component 'CopyButton': 'content' is not a string or object or function ``` Cause: - The 'CopyButton' component expect content to be a string, object or function but receives false. It does not happen in previous versions because in the refector https://github.com/odoo/odoo/commit/c2f34517b2f9832a498981d0fa17ec39b9739cb6 set the `videocall_location` to false instead of empty string like before https://github.com/odoo/odoo/blob/499420f7062ab467ff6f50b30c547e54c35ae1e9/addons/web/static/src/core/copy_button/copy_button.js#L14 - but any field using the `CopyClipboardChar/CopyClipboardURL` widget passes its raw field value straight through as content. An empty char/text field is represented as false, so whenever such a field becomes empty, CopyClipboardField hands `false` to CopyButton, which fails prop validation (debug mode). Solution: - Fix it at the source: CopyClipboardField's template now falls back to an empty string when the field value is falsy, so CopyButton never receives false but a valid string. opw-6360936 Forward-Port-Of: odoo/odoo#275236
The `selection` attribute of `fields.Selection` is not generally translated (unless it is a function instead of a list). For user facing strings, we generally need to translate the value displayed. 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#280094
Original PR description
The `selection` attribute of `fields.Selection` is not generally translated (unless it is a function instead of a list). For user facing strings, we generally need to translate the value displayed. 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#280094
Miscellaneous changes
**Steps to reproduce:** - Install Survey app - Create a survey - Share as e-mail - Add some text in the body/subject - Modify recipients - The added text is automatically reset **Issue:** Behavior was previously introduced to match the content of the composer body/subject to the recipient language. If there was only one language among the recipients it automatically adapted the template and changed the rendered language (which also refreshed the content). This logic was trigge
Original PR description
**Steps to reproduce:** - Install Survey app - Create a survey - Share as e-mail - Add some text in the body/subject - Modify recipients - The added text is automatically reset **Issue:** Behavior…
**Steps to reproduce:** - Install Survey app - Create a survey - Share as e-mail - Add some text in the body/subject - Modify recipients - The added text is automatically reset **Issue:** Behavior was previously introduced to match the content of the composer body/subject to the recipient language. If there was only one language among the recipients it automatically adapted the template and changed the rendered language (which also refreshed the content). This logic was triggered by a depends on `partner_ids` and triggered the compute on every recipient changes which led to the subject/body reset. **Fix:** Revert commit: https://github.com/odoo/odoo/commit/b7bbb7b21f4848323666230b518cad9459726f67 in 18.0+ Also adapt commit: https://github.com/odoo/odoo/commit/c6f19e89cb6019e7dbaadbc7427fbb6ddd5661ed to avoid mixed language in resulting mail when the composer was modified We could also try to prevent the compute when the subject or body is already modified instead of removing its logic. opw-6020245 Forward-Port-Of: odoo/odoo#279669 Forward-Port-Of: odoo/odoo#254090
8 changes
Enhancements to existing features
### [FIX] website: fix GMaps deprecation console warning for s_google_map Google deprecated the synchronous script loader for initializing the Maps JS API. This caused browser console warnings. The fix adopts Google's official `importLibrary()` bootstrap pattern, which loads map libraries (places, maps, marker) lazily on demand rather than all at once.The version is updated to `v=weekly`, which Google recommends as it receives updates weekly versus quarterly for version numbers(`v=num
Original PR description
### [FIX] website: fix GMaps deprecation console warning for s_google_map Google deprecated the synchronous script loader for initializing the Maps JS API. This caused browser console warnings. The…
### [FIX] website: fix GMaps deprecation console warning for s_google_map Google deprecated the synchronous script loader for initializing the Maps JS API. This caused browser console warnings. The fix adopts Google's official `importLibrary()` bootstrap pattern, which loads map libraries (places, maps, marker) lazily on demand rather than all at once.The version is updated to `v=weekly`, which Google recommends as it receives updates weekly versus quarterly for version numbers(`v=number`). Steps to reproduce: 1. Add the `s_google_map` snippet(not the`s_map`, enable debug mode) 2. Open the browser console and observe the deprecation warning ### [IMP] website: warn user to reload after GMaps config changes Switching from the legacy Google Maps APIs to the new APIs requires enabling additional services in Google Cloud. Existing maps using the legacy API continue to work, but when an admin edits a map without a proper configuration, the `GoogleMapAPIKeyDialog` dialog opens. Google Maps configuration changes (API key update or enabling services) do not take effect during the current editor session because the Maps JavaScript API is loaded at page initialization. Before this commit, such misconfigurations (disabled services or invalid API keys) only triggered a dialog showing a generic Google Maps error. After this commit, a notification informs the user that the page must be reloaded for configuration changes to take effect. The setup instructions are also updated to reference the "Places API (NEW)" service. ### [IMP] website: replace deprecated Places API calls in GPS picker The GPS picker relied on `PlacesService.nearbySearch` and `getDetails`, which are part of the deprecated Places API. The new places API replaces these with `Place.searchNearby` and `fetchFields`. Error handling is consolidated into a single try/catch since the new Places API throws on failure rather than returning a status code, removing the need for `PlacesServiceStatus` checks. ### [IMP] website, *: replace deprecated Google Autocomplete *: website_form_project google.maps.places.Autocomplete is deprecated in the new Places API. The replacement (`AutocompleteSuggestion.fetchAutocompleteSuggestions`) does not fire DOM events, making it incompatible with the old event-listener pattern used in GPSPicker. A new Owl component (`PlacesAutoComplete`) is introduced to wrap the new API, built on top of the existing `AutoCompleteWithPages`. References: https://developers.google.com/maps/documentation/javascript/load-maps-js-api https://developers.google.com/maps/documentation/javascript/advanced-markers/migration https://developers.google.com/maps/documentation/javascript/legacy/places-migration-overview task-[4441041](https://www.odoo.com/odoo/project/974/tasks/4441041) Forward-Port-Of: odoo/odoo#278344 Forward-Port-Of: odoo/odoo#242765
Before this commit, contains() and its variants gave the client 3 seconds, and the bus helpers 2 seconds. The problem is that the first wait after openDiscuss pays for the whole mount, /mail/data and /discuss/channel/messages. Measured from openDiscuss resolving to the message being in the DOM: - 250 to 460ms on an idle machine; - 867 to 5258ms over 10 runs with the CPU throttled 4x, which is what a busy runbot looks like, 3 of the 10 over 2 seconds; - 1474 to 6912ms with the CPU throttl
Original PR description
Before this commit, contains() and its variants gave the client 3 seconds, and the bus helpers 2 seconds. The problem is that the first wait after openDiscuss pays for the whole mount, /mail/data and…
Before this commit, contains() and its variants gave the client 3 seconds, and the bus helpers 2 seconds. The problem is that the first wait after openDiscuss pays for the whole mount, /mail/data and /discuss/channel/messages. Measured from openDiscuss resolving to the message being in the DOM:
- 250 to 460ms on an idle machine;
- 867 to 5258ms over 10 runs with the CPU throttled 4x, which is what a
busy runbot looks like, 3 of the 10 over 2 seconds;
- 1474 to 6912ms with the CPU throttled 6x, 5 of 6 over 3 seconds.
"Reactions are ordered by id" fails 1 run in 60 at 4x for that reason.
Note that a longer timeout costs nothing on a green build: the timer is cleared as soon as the element is there, so it only delays the report of a test that was going to fail anyway.
This commit raises both to 10 seconds, the delay a tour step already gets in macro.js. test_js.py runs the presets with timeout=15000, so hoot fails the test itself at 15 seconds and 10 leaves room for the rest of the test.
This should also close most of the open runbot errors shaped like:
Failed to find x of "..." (Timeout of 3 seconds). Found 0 instead.
The element does show up in those, just after the wait gave up.
https://runbot.odoo.com/odoo/error/944188
web companion https://github.com/odoo/odoo/pull/279984
Forward-Port-Of: odoo/odoo#279983This PR handles 2 cases : ===== PART 1 ===== Self-billing bill sequences should be unique per partner, as implemented in v19+. This PR backports that behavior to 17.0. ===== PART 2 ===== Previously, the `is_self_billing` option on `account.journal` was available only for purchase journals. This caused an issue when importing a self-billing invoice into a regular sales journal with quick edit mode (accounting firm) enabled. In such cases, the newly created invoices would use the self-
Original PR description
This PR handles 2 cases : ===== PART 1 ===== Self-billing bill sequences should be unique per partner, as implemented in v19+. This PR backports that behavior to 17.0. ===== PART 2 ===== Previously, the `is_self_billing` option on `account.journal` was available only for purchase journals. This caused an issue when importing a self-billing invoice into a regular sales journal with quick edit mode (accounting firm) enabled. In such cases, the newly created invoices would use the self-billing sequence pattern, leading to traceability issues. This PR allows the creation of self-billing sales journals to prevent this issue. task-6103142 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#276028 Forward-Port-Of: odoo/odoo#259935
Resolved issues and error corrections
Before this commit, the down payments line of the project profitability panel had no drill down action for salespersons and billing users without accounting access, because the group references were written with a trailing comma inside the XML id, making the two checks silently fail for everyone. Only the accounting read group check, written correctly, was effective. Steps to reproduce: - create a service product with "Create on Order: Project & Task", sell it on a sale order and confirm it
Original PR description
Before this commit, the down payments line of the project profitability panel had no drill down action for salespersons and billing users without accounting access, because the group references were…
Before this commit, the down payments line of the project profitability panel had no drill down action for salespersons and billing users without accounting access, because the group references were written with a trailing comma inside the XML id, making the two checks silently fail for everyone. Only the accounting read group check, written correctly, was effective. Steps to reproduce: - create a service product with "Create on Order: Project & Task", sell it on a sale order and confirm it - create a down payment invoice from the sale order and post it - create a user with Sales "User: All Documents" access, Project "User" access and no accounting access - as that user, open the dashboard of the generated project and look at the Down Payments line of the profitability panel The Down Payments amount is displayed as plain text, while a user with accounting access can click it to open the related invoices, as intended for the salesperson too. Solution: Move the commas out of the group references. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278521
Many users were receiving duplicate vendor bills. The issue was that duplicates were never detected in the receiving flow. Every incoming message returned by the proxy was processed and turned into a new `account.move`, even if it had already been imported previously. This commit filters out messages whose UUID already matches an existing `account.move` before processing them, and acknowledges those duplicates on the IAP side so they are not received again on the next run. task-5930116
Original PR description
Many users were receiving duplicate vendor bills. The issue was that duplicates were never detected in the receiving flow. Every incoming message returned by the proxy was processed and turned into a new `account.move`, even if it had already been imported previously. This commit filters out messages whose UUID already matches an existing `account.move` before processing them, and acknowledges those duplicates on the IAP side so they are not received again on the next run. task-5930116 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275992 Forward-Port-Of: odoo/odoo#274963
In _validate_amount(), setting a "Percentage of balance" line to 0 raises "Statement line percentage can't be 0", and setting a "Percentage of statement line" to 0 raises "Balance percentage can't be 0". Align each error message with the amount type being validated. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#269393
Original PR description
In _validate_amount(), setting a "Percentage of balance" line to 0 raises "Statement line percentage can't be 0", and setting a "Percentage of statement line" to 0 raises "Balance percentage can't be 0". Align each error message with the amount type being validated. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#269393
Microsoft issues a new refresh token on every access token refresh (rolling 90-day sliding window). The previous code discarded it, causing users to be forced to re-authenticate every 90 days once the original token expired. Closes #253543 Forward-Port-Of: odoo/odoo#274701 Forward-Port-Of: odoo/odoo#268284
Original PR description
Microsoft issues a new refresh token on every access token refresh (rolling 90-day sliding window). The previous code discarded it, causing users to be forced to re-authenticate every 90 days once the original token expired. Closes #253543 Forward-Port-Of: odoo/odoo#274701 Forward-Port-Of: odoo/odoo#268284
### Issue: A partner with VAT set to '/' incorrectly matches a fiscal position with `VAT required`, instead of one without The '/' value is the placeholder suggested by the UI to indicate that the partner is known to have no VAT, but it was treated as a valid VAT by the fiscal position matching logic ### Cause: `_get_fpos_ranking_functions` uses `_get_vat_valid` to rank fiscal positions based on VAT presence `_get_vat_valid` returned `True` for any non-empty VAT value, including '/' Th
Original PR description
### Issue: A partner with VAT set to '/' incorrectly matches a fiscal position with `VAT required`, instead of one without The '/' value is the placeholder suggested by the UI to indicate that the partner is known to have no VAT, but it was treated as a valid VAT by the fiscal position matching logic ### Cause: `_get_fpos_ranking_functions` uses `_get_vat_valid` to rank fiscal positions based on VAT presence `_get_vat_valid` returned `True` for any non-empty VAT value, including '/' The '/' case was not excluded, causing it to be treated as a valid VAT number ### Steps to reproduce: - Install `account` - Create two fiscal positions with auto-apply: -- Name: FP VAT, VAT required: True, sequence: 1 -- Name: FP no VAT, VAT required: False, sequence: 2 - Create a partner with VAT: '/' - Create an Invoice for that partner and check the Fiscal Position Before the fix, `FP VAT` is selected instead of `FP no VAT` opw-6204531 Forward-Port-Of: odoo/odoo#280065
11 changes
Enhancements to existing features
Doing an euclidean division on floats with the native operators is unreliable: because of IEEE-754 representation errors, `value1 % value2` can return a spurious remainder (e.g. `50.4 % 16.8 == 16.799999999999997` instead of 0.0) and `int(value1 / value2)` can truncate the quotient one step too low (e.g. `int(0.3 / 0.1) == 2` instead of 3). `float_div` returns the `(quotient, remainder)` pair free of those errors. The key is to never run a lossy `%` or `//` on the raw floats. Instead both ope
Original PR description
Doing an euclidean division on floats with the native operators is unreliable: because of IEEE-754 representation errors, `value1 % value2` can return a spurious remainder (e.g. `50.4 % 16.8 ==…
Doing an euclidean division on floats with the native operators is unreliable: because of IEEE-754 representation errors, `value1 % value2` can return a spurious remainder (e.g. `50.4 % 16.8 == 16.799999999999997` instead of 0.0) and `int(value1 / value2)` can truncate the quotient one step too low (e.g. `int(0.3 / 0.1) == 2` instead of 3). `float_div` returns the `(quotient, remainder)` pair free of those errors. The key is to never run a lossy `%` or `//` on the raw floats. Instead both operands are first snapped onto the precision grid with `float_round` and then scaled to integers: since a grid-snapped value is a multiple of `rounding`, dividing it by `rounding` counts how many grid steps it spans. That division is still noisy (`4.35 / 0.05 == 86.99999999999999`), so the result is passed through `builtins.round` to coerce it to the exact integer step count. The euclidean division itself is then a plain integer `divmod`, which is exact, and the remainder is scaled back to real units. This is why the correction is applied to the inputs and not to the output: rounding the result of a native `%` would only round an already-corrupt value, and would still misreport the quotient in the corner cases the util exists to handle. Dividing by `rounding` is meaningful for any precision, not only powers of ten: the grid step can be `0.05`, `0.25`, `0.5`, `0.03`, ... and `value / step` counts the steps in every case. This mirrors the normalize/denormalize scheme `float_round` already uses internally. The util shares `float_round`'s inherent limitation: the scaled step count must stay representable as an exact `float` integer, so exactness is lost past ~2**53 grid steps (extreme magnitudes at a fine precision). This is the IEEE-754 double-precision ceiling and is well outside any realistic quantity or price range. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites in addons tests reach waitForSteps and not one of them passes an explicit timeout, so 2 seconds is what every step wait gets. The problem is that the RPC chain a step wait sits on takes longer than that on a loaded machine. Measured from openDiscuss resolving to the message being in the DOM: -
Original PR description
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites…
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites in addons tests reach waitForSteps and not one of them passes an explicit timeout, so 2 seconds is what every step wait gets. The problem is that the RPC chain a step wait sits on takes longer than that on a loaded machine. Measured from openDiscuss resolving to the message being in the DOM: - 250 to 460ms on an idle machine; - 867 to 5258ms over 10 runs with the CPU throttled 4x, which is what a busy runbot looks like, 3 of the 10 over 2 seconds; - 1474 to 6912ms with the CPU throttled 6x, 5 of 6 over 3 seconds. Note that a longer timeout costs nothing on a green build: the timer is cleared as soon as the steps are in, so it only delays the report of a test that was going to fail anyway. This commit raises both to 10 seconds, the delay a tour step already gets in macro.js. test_js.py runs the presets with timeout=15000, so hoot fails the test itself at 15 seconds and 10 leaves room for the rest of the test. Companion of https://github.com/odoo/odoo/pull/279983 to fix https://runbot.odoo.com/odoo/error/944188 kind of issues.
This commit adds 3 new `Tax Exemption Reason Code`: - VATEX-FR-F - VATEX-FR-I - VATEX-FR-J task-6333649
Original PR description
This commit adds 3 new `Tax Exemption Reason Code`: - VATEX-FR-F - VATEX-FR-I - VATEX-FR-J task-6333649
Resolved issues and error corrections
### Issue: A partner with VAT set to '/' incorrectly matches a fiscal position with `VAT required`, instead of one without The '/' value is the placeholder suggested by the UI to indicate that the partner is known to have no VAT, but it was treated as a valid VAT by the fiscal position matching logic ### Cause: `_get_fpos_ranking_functions` uses `_get_vat_valid` to rank fiscal positions based on VAT presence `_get_vat_valid` returned `True` for any non-empty VAT value, including '/' Th
Original PR description
### Issue: A partner with VAT set to '/' incorrectly matches a fiscal position with `VAT required`, instead of one without The '/' value is the placeholder suggested by the UI to indicate that the partner is known to have no VAT, but it was treated as a valid VAT by the fiscal position matching logic ### Cause: `_get_fpos_ranking_functions` uses `_get_vat_valid` to rank fiscal positions based on VAT presence `_get_vat_valid` returned `True` for any non-empty VAT value, including '/' The '/' case was not excluded, causing it to be treated as a valid VAT number ### Steps to reproduce: - Install `account` - Create two fiscal positions with auto-apply: -- Name: FP VAT, VAT required: True, sequence: 1 -- Name: FP no VAT, VAT required: False, sequence: 2 - Create a partner with VAT: '/' - Create an Invoice for that partner and check the Fiscal Position Before the fix, `FP VAT` is selected instead of `FP no VAT` opw-6204531
Before this commit, turning the camera on during a call could leave the camera off in every member's UI, including the local user's own tile, while the video was already being sent. This happens because toggleVideo awaits network.updateUpload before updateAndBroadcast, and updateUpload waits on the ready promise of every peer. A single member whose handshake never completes holds isCameraOn and isScreenSharingOn for everyone. This commit fixes the issue by broadcasting the state first and
Original PR description
Before this commit, turning the camera on during a call could leave the camera off in every member's UI, including the local user's own tile, while the video was already being sent. This happens because toggleVideo awaits network.updateUpload before updateAndBroadcast, and updateUpload waits on the ready promise of every peer. A single member whose handshake never completes holds isCameraOn and isScreenSharingOn for everyone. This commit fixes the issue by broadcasting the state first and awaiting the upload after. Note that updateUpload sends its info snapshot to the peers synchronously, so they still learn the new track. Back-port of https://github.com/odoo/odoo/pull/279106
**Steps to reproduce:** 1. Install Accounting and l10n_be and switch to the Belgian company 2. In the settings, set the discount account (`708000`) on Customer Invoices under "Default Accounts" and enable analytic accounting 3. Go to [Accounting -> Configuration -> Analytic Accounts] and create 4 new accounts with "Project" plan (i.e 1,2,3,4) 4. Create a new invoice with two lines, each having 2 of the analytic accounts with 50% each. 5. Set the price to 1000 and a 10% discount for each lin
Original PR description
**Steps to reproduce:** 1. Install Accounting and l10n_be and switch to the Belgian company 2. In the settings, set the discount account (`708000`) on Customer Invoices under "Default Accounts" and…
**Steps to reproduce:** 1. Install Accounting and l10n_be and switch to the Belgian company 2. In the settings, set the discount account (`708000`) on Customer Invoices under "Default Accounts" and enable analytic accounting 3. Go to [Accounting -> Configuration -> Analytic Accounts] and create 4 new accounts with "Project" plan (i.e 1,2,3,4) 4. Create a new invoice with two lines, each having 2 of the analytic accounts with 50% each. 5. Set the price to 1000 and a 10% discount for each line then save. 6. Edit the second line and set the discount to 20%. 7. Open the Journal Items tab **Issue:** - When an invoice contains multiple lines with analytic distributions, changing the discount percentage on any line other than the first fails to correctly update the analytic distribution percentages on the corresponding discount journal items. - The analytic account distribution splits the percentage evenly across both accounts event if they are not split 50/50 **Why this happens:** - This occurred because `_compute_discount_allocation_needed` iterated over `self` to populate target changes. When only one line was modified, `self` contains that line only which is correctly updated with the new analytic distribution. Later in the execution in `_sync_dynamic_line`, particularly in https://github.com/odoo/odoo/blob/5a14360705a55f4d91edf39c936d7a5d8573044b/addons/account/models/account_move.py#L2263-L2274 The first line in `computed_needed` is what gets set in res, and subsequent lines only modify the field if it's monetary. So if the second invoice line is the one updated, it will never override the `analytic_distribution` with the updated values, leaving stale values in that field. - The code iterated directly over `line.analytic_distribution` dictionary keys (the account IDs) rather than its `.items()`. This caused it to ignore the individual percentage value splits (e.g. 60/40), accumulating the un-weighted full discount amount to each account ID. https://github.com/odoo/odoo/blob/5a14360705a55f4d91edf39c936d7a5d8573044b/addons/account/models/account_move_line.py#L1044-L1052 **Fix:** - Change the processing loop inside `_compute_discount_allocation_needed` from `self` to `self.move_id.line_ids` to calculate the correct `analytic_distribution` across all records. - Applying the factored weight ratio (`amount * (percentage / 100.0)`) to `distribution_totals` opw-6362084 Forward-Port-Of: odoo/odoo#275070
### Steps to reproduce the issue: 1. Download Accounting and l10n_de 2. Set VAT number for DE company and another company you will use for the invoice 3. Switch to german language 4. Create an invoice and send it 5. Download the PDF and upload it on www.portinvoice.com 6. See the following error: the PDF metadata incorrectly states the conformance level as "ERWEITERT" (German), which directly clashes with the correct "EXTENDED" (English) profile declared inside the embedded XML file. ##
Original PR description
### Steps to reproduce the issue: 1. Download Accounting and l10n_de 2. Set VAT number for DE company and another company you will use for the invoice 3. Switch to german language 4. Create an invoice and send it 5. Download the PDF and upload it on www.portinvoice.com 6. See the following error: the PDF metadata incorrectly states the conformance level as "ERWEITERT" (German), which directly clashes with the correct "EXTENDED" (English) profile declared inside the embedded XML file. ### Cause of the issue: Issue comes from this commit 9396790e9cc1ce1c6e5c29b71b5629b31fb16458 where it has been forgotten to disable the translation. ### Reason to introduce the fix: Meet the requirements of the electronic invoice. opw-6023971 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273042
Currently, if you have a partner with Belgian VAT as peppol eas, but no peppol endpoint, you get a traceback when you open the Send&Print. It can happen easily, if you have customers without VAT or company registry, that were created 2 years ago, when we put Belgian VAT as default. 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
Original PR description
Currently, if you have a partner with Belgian VAT as peppol eas, but no peppol endpoint, you get a traceback when you open the Send&Print. It can happen easily, if you have customers without VAT or company registry, that were created 2 years ago, when we put Belgian VAT as default. 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
This commit is a backport of the extra timeout added in the forward port in commit 75e9ec3e9ae041d5509bd0f6c62128d1075b0135 The previous step trigger a reload of the iframe because the template for the header is changed, which takes some time. This causes non-deterministic failure due timeout. Thus, the timeout is increased. runbot-234060
Original PR description
This commit is a backport of the extra timeout added in the forward port in commit 75e9ec3e9ae041d5509bd0f6c62128d1075b0135 The previous step trigger a reload of the iframe because the template for the header is changed, which takes some time. This causes non-deterministic failure due timeout. Thus, the timeout is increased. runbot-234060
Before this commit, this test was failing non-deterministically on on some machines: ``` show banner for new message after thread was read from another device ``` With the following error: ``` Error: Failed to find 1 of ".o-mail-Thread-banner:has(:text('1 new message'))" (Timeout of 3 seconds). Found 0 instead. ``` This happens because while the message list has 20 messages, each message is 1-line long. That means on many monitors the bottom of conversation is visible and thus it c
Original PR description
Before this commit, this test was failing non-deterministically on on some machines:
```
show banner for new message after thread was read from another device
```
With the following error:
```
Error: Failed to find 1 of ".o-mail-Thread-banner:has(:text('1 new message'))" (Timeout of 3 seconds). Found 0 instead.
```
This happens because while the message list has 20 messages, each message is 1-line long. That means on many monitors the bottom of conversation is visible and thus it can mark as read automatically the conversation. When this happens the banner is removed, thus the last step would fail.
This commit fixes the issue by making each message body bigger, so that this is very unlikely to see the bottom of message list, therefore avoiding the auto-mark as read from reaching the bottom of conversation.Steps to reproduce: - Install 'Sales', 'Accounting' and 'l10n_sa_edi' - Settings > Accounting > Rounding Method > Round Globally - Create an invoice whose per-line tax base is fractional (e.g. a price-included 15% VAT, 3 lines at 10.00 -> base 8.6957 each) - Generate the ZATCA UBL document Issue: The exported document is internally inconsistent and is rejected by ZATCA (BR-CO-13): cbc:LineExtensionAmount (BT-106) = 26.10 while cbc:TaxExclusiveAmount (BT-109), and thus the QR / PayableAmo
Original PR description
Steps to reproduce: - Install 'Sales', 'Accounting' and 'l10n_sa_edi' - Settings > Accounting > Rounding Method > Round Globally - Create an invoice whose per-line tax base is fractional (e.g. a…
Steps to reproduce: - Install 'Sales', 'Accounting' and 'l10n_sa_edi' - Settings > Accounting > Rounding Method > Round Globally - Create an invoice whose per-line tax base is fractional (e.g. a price-included 15% VAT, 3 lines at 10.00 -> base 8.6957 each) - Generate the ZATCA UBL document Issue: The exported document is internally inconsistent and is rejected by ZATCA (BR-CO-13): cbc:LineExtensionAmount (BT-106) = 26.10 while cbc:TaxExclusiveAmount (BT-109), and thus the QR / PayableAmount (BT-115), = 26.09. This is the same 0.01 discrepancy reported for 100% down-payment invoices under global rounding. Cause: LineExtensionAmount was built by summing account.move.line.price_subtotal, which is always rounded per line (8.70 x 3 = 26.10), whereas TaxExclusiveAmount is built from the aggregated base_amount_currency, which follows the company rounding method and is rounded globally (26.087 -> 26.09). Under 'round_globally' the two diverge by a cent. This is the base-amount counterpart of commit 3d398789, which aligned the prepaid tax amount to global rounding but left the line net amount on per-line rounding. Solution: Derive the line net amount from the globally-rounded aggregated base (taxes_vals['base_amount_currency']) https://github.com/odoo/odoo/blob/c7c361e6af4da43dc1f9653703067ffe6500a046/addons/account/models/account_tax.py#L1529 instead of the per-line rounded price_subtotal, consistent with total_amount_sa on the same line. The whole document now stays on a single rounding basis, so the sum of the line net amounts equals the TaxExclusiveAmount and BR-CO-13 is satisfied. opw-5881564
2 changes
Resolved issues and error corrections
Steps to reproduce the error: (Python Version: 3.14.X) - Install ``accounting_firm`` industry with demo data Code for server action to generate the error: ```py for i in [1]: try: pass except Exception: pass if i: pass ``` Traceback: ```py ValueError: forbidden opcode(s) in'...': JUMP_BACKWARD_NO_INTERRUPT ``` https://github.com/odoo/industry/blob/701f7595453772e42ce72aa75df346a504e5bd82/accounting_firm/demo/ir_actions_server.xml#L105-L10
Original PR description
Steps to reproduce the error: (Python Version: 3.14.X) - Install ``accounting_firm`` industry with demo data Code for server action to generate the error: ```py for i in [1]: try: pass except…
Steps to reproduce the error: (Python Version: 3.14.X)
- Install ``accounting_firm`` industry with demo data
Code for server action to generate the error:
```py
for i in [1]:
try:
pass
except Exception:
pass
if i:
pass
```
Traceback:
```py
ValueError: forbidden opcode(s) in'...': JUMP_BACKWARD_NO_INTERRUPT
```
https://github.com/odoo/industry/blob/701f7595453772e42ce72aa75df346a504e5bd82/accounting_firm/demo/ir_actions_server.xml#L105-L108
The server action contains a ``for`` loop with a ``try/except`` block followed by additional statements in the loop body,
this combination generates the ``JUMP_BACKWARD_NO_INTERRUPT`` opcode, which is not included in ``_SAFE_OPCODES`` at [1].
When the server action is evaluated by ``safe_eval``, it calls the ``assert_valid_codeobj`` method, which validates the compiled bytecode against ``_SAFE_OPCODES``. Since ``JUMP_BACKWARD_NO_INTERRUPT`` is not present in the allowed opcodes, ``assert_valid_codeobj()`` raises a ``ValueError`` at [2] before the server action is executed .
Solution:
``JUMP_BACKWARD_NO_INTERRUPT`` opcode is added in the ``_SAFE_OPCODES`` and it is also added in the ``_SAFE_QWEB_OPCODES``.
It was added in Python 3.11: https://docs.python.org/3/whatsnew/3.11.html#new-opcodes
``JUMP_BACKWARD_NO_INTERRUPT`` is a control-flow opcode that only changes
the interpreter's execution flow by jumping back to a previous instruction.
It is the equivalent to ``JUMP_BACKWARD`` opcode. Its only semantic difference is
that the interpreter does not perform an interrupt check at that instruction.
It does not introduce any new capabilities or perform operations such as
attribute access, imports, function calls, or object creation.
Ref: https://docs.python.org/3.12/library/dis.html#opcode-JUMP_BACKWARD_NO_INTERRUPT
Similar commit that adds some necessary opcodes:
https://github.com/odoo/odoo/commit/86498d24946e510025add5d24ef0d4bcce8ad05f
[1]: https://github.com/odoo/odoo/blob/2ccbc4660077bd48529e9de43d4309fbfafc75ca/odoo/tools/safe_eval.py#L135
[2]: https://github.com/odoo/odoo/blob/2ccbc4660077bd48529e9de43d4309fbfafc75ca/odoo/tools/safe_eval.py#L244-L246
sentry-7614026125
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prMiscellaneous changes
Commit: 68343a56ef0e727c8ac0be4875bedd0fb7460d04 added the possibility of having a negative value for taxable amount in zatca xml to fix this warning: [202] BR-O-08 : [BR-O-08]-In a VAT breakdown (BG-23) where the VAT category code (BT-118) is ' Not subject to VAT' the VAT category taxable amount (BT-116) shall equal the sum of Invoice line net amounts (BT-131) minus the sum of Document level allowance amounts (BT-92) plus the sum of Document level charge amounts (BT-99) where the VAT catego
Original PR description
Commit: 68343a56ef0e727c8ac0be4875bedd0fb7460d04 added the possibility of having a negative value for taxable amount in zatca xml to fix this warning: [202] BR-O-08 : [BR-O-08]-In a VAT breakdown…
Commit: 68343a56ef0e727c8ac0be4875bedd0fb7460d04 added the possibility of having a negative value for taxable amount in zatca xml to fix this warning: [202] BR-O-08 : [BR-O-08]-In a VAT breakdown (BG-23) where the VAT category code (BT-118) is ' Not subject to VAT' the VAT category taxable amount (BT-116) shall equal the sum of Invoice line net amounts (BT-131) minus the sum of Document level allowance amounts (BT-92) plus the sum of Document level charge amounts (BT-99) where the VAT category codes (BT-151, BT-95, BT-102) are 'Not subject to VAT'. However you cannot have a negative value for this node as stipulated by: BR-KSA-F-04 All the document amounts and quantities must be positive. ubl:Invoice / ubl:Invoice / cac:AllowanceCharge / cbc:Amount / ubl:Invoice / cac:AllowanceCharge / cbc:BaseAmount / ubl:Invoice / cac:TaxTotal / cbc:TaxAmount / ubl:Invoice / cac:TaxTotal / cac:TaxSubtotal / cbc:TaxableAmount (source: https://zatca.gov.sa/ar/E-Invoicing/SystemsDevelopers/Documents/20220624_ZATCA_Electronic_Invoice_XML_Implementation_Standard_vF.pdf) The reverted commit causes an error when sending an invoice with a 0% or a sale order with a down payment: - Create a sale order with a 0%. - Create a downpayment and process it by zatca - Process the delivery on the SO and create the final invoice. - The invoice will be rejected by zata with the error: BR-KSA-80 If Pre-Paid amount (BT-113) is provided then the Pre-Paid amount (BT-113) must equal to the sum total of the Prepayment VAT category Taxable Amount (KSA-31) and Prepayment VAT Category Tax Amount (KSA-32) opw-5072577 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