Daily updates from Odoo
Wednesday, July 29, 2026
235 changes
3 changes
Resolved issues and error corrections
Issue: When a shopper pays for an online order entirely using a reward (e.g. a discount code covering 100% of the total), the order total is zero. With automatic invoicing enabled, an invoice with an amount of 0 is created. But, the 0 invoice is never emailed to the customer. Whereas, for orders where the total is more than 0, an invoice is created, then emailed to the customer. The customer should be emailed the invoice, even if its amount is 0. Steps to reproduce: 1. Enable automatic invo
Original PR description
Issue: When a shopper pays for an online order entirely using a reward (e.g. a discount code covering 100% of the total), the order total is zero. With automatic invoicing enabled, an invoice with an…
Issue: When a shopper pays for an online order entirely using a reward (e.g. a discount code covering 100% of the total), the order total is zero. With automatic invoicing enabled, an invoice with an amount of 0 is created. But, the 0 invoice is never emailed to the customer. Whereas, for orders where the total is more than 0, an invoice is created, then emailed to the customer. The customer should be emailed the invoice, even if its amount is 0. Steps to reproduce: 1. Enable automatic invoicing. 2. Create a code for a 100% discount. 3. As a shopper, add a product to cart on the website. 4. While checking out, apply the 100% discount code to the order. 5. Complete the checkout. 6. Confirm that an invoice was created and posted, but was not emailed to the customer. Explanation: Normally, order confirmation and invoicing are handled by the `_post_process` method on the `payment.transaction` model. With automatic invoicing enabled, `_post_process` confirms the sale order, creates the invoice, and sends the invoice via `_send_invoice` (another method on the `payment.transaction` model). If `sale.async_emails` is enabled, `_post_process` will trigger a cron that invokes `_send_invoice` instead of invoking it directly. When an order is fully covered by a reward, there's nothing to pay. In this case, no payment.transaction record is ever created, and `_post_process` never runs. Instead, the order is confirmed through the `_validate_order` method on the `sale.order` model. The `sale_loyalty` module extends `_validate_order` so that, with automatic invoicing enabled, it will create and post an invoice for zero-amount orders. But, nothing in this path ever calls `_send_invoice` or an equivalent. So, the invoice is created and posted but never sent. Solution: This adds logic for sending invoices to the extension of `_validate_order` in the `sale_loyalty` module. We mirror the logic used in `_send_invoice` in the `payment.transaction` model. Notes: There is duplicated code from `_send_invoice` in this fix. That is because `_send_invoice`, a method on the `payment.transaction` model, can't be used in this flow. A fix that avoids code duplication would require serious refactoring. This will never trigger a cron to send the invoice, even if `sale.async_emails` is enabled. That is because the cron invokes `_send_invoice`. Since fully reward-covered orders are probably not common, any performance benefits of using a cron are probably not significant. But, making a new cron to be used in this case is also an option. opw-6363334 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277970 Forward-Port-Of: odoo/odoo#275190
The bugfix introduced in https://github.com/odoo/odoo/commit/01d11a770f89c391f7c6a2c46a3d770d10afb428 made it so that "personal" outgoing mail servers are blocked/ignored from being used in email marketing as dedicated servers. In doing so, it missed the fact that while in *Email Marketing > Settings*, the "Dedicated Server" picker now correctly ignores personal OMS entries, the selection widget for `mail_server_id` in `view_mail_mass_mailing_form` still let's you manually select a OMS with a
Original PR description
The bugfix introduced in https://github.com/odoo/odoo/commit/01d11a770f89c391f7c6a2c46a3d770d10afb428 made it so that "personal" outgoing mail servers are blocked/ignored from being used in email…
The bugfix introduced in https://github.com/odoo/odoo/commit/01d11a770f89c391f7c6a2c46a3d770d10afb428 made it so that "personal" outgoing mail servers are blocked/ignored from being used in email marketing as dedicated servers.
In doing so, it missed the fact that while in *Email Marketing > Settings*, the "Dedicated Server" picker now correctly ignores personal OMS entries, the selection widget for `mail_server_id` in `view_mail_mass_mailing_form` still let's you manually select a OMS with an owner set. As there is not warning or an explicit error, this can lead to accidental miss configurations on an email marketing campaign, where the selected OMS will be actually ignored by the backend.
To align the changes introduced by the bugfix, we add a search domain to the selection field, so that only OMS with `('owner_user_id', '=', False)` will be presented as a choice.
OPW-6388562
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#278918
Forward-Port-Of: odoo/odoo#278595Miscellaneous changes
### before ~1.4s <img width="1869" height="819" alt="image" src="https://github.com/user-attachments/assets/168e3831-929b-43fd-9aa1-ea5bfb22d3fe" /> ### after ~570ms <img width="1862" height="860" alt="image" src="https://github.com/user-attachments/assets/ea907064-fe12-4711-9707-67926f05cedf" /> See commit messages --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274360
Original PR description
### before ~1.4s <img width="1869" height="819" alt="image" src="https://github.com/user-attachments/assets/168e3831-929b-43fd-9aa1-ea5bfb22d3fe" /> ### after ~570ms <img width="1862" height="860" alt="image" src="https://github.com/user-attachments/assets/ea907064-fe12-4711-9707-67926f05cedf" /> See commit messages --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274360
14 changes
Resolved issues and error corrections
# How to reproduce - Have two language in the db - Create an e-Commerce category - Have a different translation for each language for that category's name - Copy the link to that category's name in one language (Should be something like /shop/category/name-x) - Have two websites, each with a different default language - Create a link to the shop category in each website. > ! The link must be the exact same > You can put it in the header menu for simplicity - Open the website editor - D
Original PR description
# How to reproduce - Have two language in the db - Create an e-Commerce category - Have a different translation for each language for that category's name - Copy the link to that category's name in…
# How to reproduce
- Have two language in the db
- Create an e-Commerce category
- Have a different translation for each language for that category's name
- Copy the link to that category's name in one language (Should be something like /shop/category/name-x)
- Have two websites, each with a different default language
- Create a link to the shop category in each website.
> ! The link must be the exact same
> You can put it in the header menu for simplicity
- Open the website editor
- Do 2 or 3 times :
- click on the category link and switch website
# The issue
A traceback is displayed
# Cause
This manipulation will make us enter an infinite redirect scenario described here :
https://github.com/odoo/odoo/blob/f8741728294a5147c7d2427d9997738096386262/addons/website/static/src/client_actions/website_preview/website_builder_action.js#L371-L384
The problem is that this commit introduced an assignation to `iframe.contentDocument.body` before the patch :
https://github.com/odoo/odoo/commit/89994eb7a54ca606bab26b6d579d03e86c11ba60
But in our case, iframe.contentDocument is null, so it throws an error before the patch can be applied
opw-6322115
Forward-Port-Of: odoo/odoo#276634Unlocking a validated MO to add a new component move should, naturally, bring about a validated move. Although there exists a `state` check in `stock.move`'s `create()` as of odoo/odoo#196161, it only checks for `picking_id`, whereas a component move has a `raw_material_production_id` (and a finished (by)product has a `production_id`), so we replicate the check here. Task ID: [6226710](https://www.odoo.com/odoo/project/966/tasks/6226710) Forward-Port-Of: odoo/odoo#267186
Original PR description
Unlocking a validated MO to add a new component move should, naturally, bring about a validated move. Although there exists a `state` check in `stock.move`'s `create()` as of odoo/odoo#196161, it only checks for `picking_id`, whereas a component move has a `raw_material_production_id` (and a finished (by)product has a `production_id`), so we replicate the check here. Task ID: [6226710](https://www.odoo.com/odoo/project/966/tasks/6226710) Forward-Port-Of: odoo/odoo#267186
Once the cron is called to update current_version_id, the new employee calendar is applied to the previous version as well, due to the inverse on resource.resource def _inverse_calendar_id(self): for resource in self: if resource.calendar_id != resource.employee_id.resource_calendar_id: resource.employee_id.resource_calendar_id = resource.calendar_id All that because the introduced piece of code was called before super if 'current_versi
Original PR description
Once the cron is called to update current_version_id, the new employee calendar is applied to the previous version as well, due to the inverse on resource.resource
def _inverse_calendar_id(self):
for resource in self:
if resource.calendar_id != resource.employee_id.resource_calendar_id:
resource.employee_id.resource_calendar_id = resource.calendar_id
All that because the introduced piece of code was called before super
if 'current_version_id' in vals:
new_version = self.env['hr.version'].browse(vals.get('current_version_id'))
self.resource_id.calendar_id = new_version.resource_calendar_id
And this the inverse method was called on the previous version (not yet updated), not the new one.
Forward-Port-Of: odoo/odoo#279048## Problem When a `web_read_group` call is made with some condition on the active field, the active test is bypassed by adding `['active', 'in', [True, False]]` to the domain. This will cause a search to fail if the model's active field is not called `active` (like in a studio model). ## Solution We will change the domain to `[self._active_name, 'in', [True, False]]` to properly handle customizations. ## Steps to replicate (Runbot v19) 1. Create a new model with Studio - enable Pipeline
Original PR description
## Problem When a `web_read_group` call is made with some condition on the active field, the active test is bypassed by adding `['active', 'in', [True, False]]` to the domain. This will cause a search to fail if the model's active field is not called `active` (like in a studio model). ## Solution We will change the domain to `[self._active_name, 'in', [True, False]]` to properly handle customizations. ## Steps to replicate (Runbot v19) 1. Create a new model with Studio - enable Pipeline and Archiving 2. Open the kanban view and add 'Archived' to the filter 3. Traceback opw-6403422 Forward-Port-Of: odoo/odoo#277908 Forward-Port-Of: odoo/odoo#277666
`_get_belgian_cocontractant_note()` resolves the co-contractant fiscal position through chart_template.ref(), which uses env.company. The "Send invoices automatically" cron runs as the inactive OdooBot user, so env.company is OdooBot's default company, not the invoice's. That company can differ from the invoice's and even be archived, in which case ref() raises "IndexError: tuple index out of range" (parent_ids is empty for an archived company) Steps to reproduce: - Set the main company to a
Original PR description
`_get_belgian_cocontractant_note()` resolves the co-contractant fiscal position through chart_template.ref(), which uses env.company. The "Send invoices automatically" cron runs as the inactive OdooBot user, so env.company is OdooBot's default company, not the invoice's. That company can differ from the invoice's and even be archived, in which case ref() raises "IndexError: tuple index out of range" (parent_ids is empty for an archived company) Steps to reproduce: - Set the main company to a non-Belgian company, and invoice from another active Belgian company. - Move every active user off the main company and archive it - Send a Belgian 0% invoice through the cron. => IndexError: tuple index out of range in chart_template.ref opw-6398778 Forward-Port-Of: odoo/odoo#278666 Forward-Port-Of: odoo/odoo#278326
- Fix: The edit() calls now pass { confirm: false } to avoid calling the extra step that involved clicking manually on the input to trigger the search and the dropdown display. This should remove the race condition. - Small cleanup: clickFieldDropdownItem replaces the hardcoded ".dropdown-item:nth-child(1)" click, allowing selecting by product name instead of position. runbot-error: 941390 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-P
Original PR description
- Fix: The edit() calls now pass { confirm: false } to avoid calling the extra step that involved clicking manually on the input to trigger the search and the dropdown display. This should remove the race condition.
- Small cleanup: clickFieldDropdownItem replaces the hardcoded ".dropdown-item:nth-child(1)" click, allowing selecting by product name instead of position.
runbot-error: 941390
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#278813When an order/invoice is fully discounted by a global discount, its base and tax amounts are sums of values each already rounded to the currency precision, so their sum is only a sub-unit floating point residue (~1e-6) instead of a clean zero. `_get_tax_totals_summary` fed that raw sum straight to the cash rounding. With a 'UP' (or 'DOWN') rounding method the residue was inflated into a full rounding step, e.g. a 0.01 total to pay on an otherwise empty document. opw-6402143 --- I confi
Original PR description
When an order/invoice is fully discounted by a global discount, its base and tax amounts are sums of values each already rounded to the currency precision, so their sum is only a sub-unit floating point residue (~1e-6) instead of a clean zero. `_get_tax_totals_summary` fed that raw sum straight to the cash rounding. With a 'UP' (or 'DOWN') rounding method the residue was inflated into a full rounding step, e.g. a 0.01 total to pay on an otherwise empty document. opw-6402143 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278291
When the shop sidebar categories are enabled with collapsed categories, subcategory names could wrap unexpectedly at 100% zoom or lower, even when there was enough available space. Steps to reproduce: - Open the Shop page and click Edit - Go to the Style tab - Set Content Width to Full - Enable the Categories sidebar - Enable Collapse Category This issue caused sidebar subcategory labels to wrap only at lower zoom levels, while higher zoom levels displayed them correctly. Add CSS
Original PR description
When the shop sidebar categories are enabled with collapsed categories, subcategory names could wrap unexpectedly at 100% zoom or lower, even when there was enough available space. Steps to reproduce: - Open the Shop page and click Edit - Go to the Style tab - Set Content Width to Full - Enable the Categories sidebar - Enable Collapse Category This issue caused sidebar subcategory labels to wrap only at lower zoom levels, while higher zoom levels displayed them correctly. Add CSS rules to prevent category names in the sidebar from wrapping. opw-6296804 Forward-Port-Of: odoo/odoo#275279
When receiving a Peppol/UBL XML file containing an embedded PDF via an email alias, the PDF is not extracted and attached to the resulting vendor bill. Steps to reproduce: - Set up a BE Company - Configure an incoming mail server - Set up an email alias for the Vendor Bill journal - Receive a Peppol XML with embedded PDF via alias - Check the created Bill Issue: PDF has not been extracted from the xml This occurs because the received xml is set as main attachment for the record a
Original PR description
When receiving a Peppol/UBL XML file containing an embedded PDF via an email alias, the PDF is not extracted and attached to the resulting vendor bill. Steps to reproduce: - Set up a BE Company - Configure an incoming mail server - Set up an email alias for the Vendor Bill journal - Receive a Peppol XML with embedded PDF via alias - Check the created Bill Issue: PDF has not been extracted from the xml This occurs because the received xml is set as main attachment for the record and in this case we skip extraction opw-6075250 Forward-Port-Of: odoo/odoo#278806 Forward-Port-Of: odoo/odoo#262047
When `cash_rounding` is enabled on a POS config but `rounding_method` is not set,`get_tax_totals_summary` is called with undefined (instead of null). Fix: ensure the `rounding_method` is set when `cash_rounding` is enabled, otherwise pass null to `get_tax_totals_summary`. task-id: 6388234 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278144 Forward-Port-Of: odoo/odoo#276914
Original PR description
When `cash_rounding` is enabled on a POS config but `rounding_method` is not set,`get_tax_totals_summary` is called with undefined (instead of null). Fix: ensure the `rounding_method` is set when `cash_rounding` is enabled, otherwise pass null to `get_tax_totals_summary`. task-id: 6388234 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278144 Forward-Port-Of: odoo/odoo#276914
In the current state, running `test_qris_link_with_pos_order` results in an access error. This is because the user is missing the PoS group user access group. This PR changes the test class inheritance from `AccountTestInvoicingHttpCommon` to `TestPointOfSaleHttpCommon`. This provides the necessary PoS setup. I also had to change mentions of `pos_user`, as the qris test class created its own `pos_user` distinct from its ancestor's. Error page: https://runbot.odoo.com/odoo/error/938918
Original PR description
In the current state, running `test_qris_link_with_pos_order` results in an access error. This is because the user is missing the PoS group user access group. This PR changes the test class inheritance from `AccountTestInvoicingHttpCommon` to `TestPointOfSaleHttpCommon`. This provides the necessary PoS setup. I also had to change mentions of `pos_user`, as the qris test class created its own `pos_user` distinct from its ancestor's. Error page: https://runbot.odoo.com/odoo/error/938918
Following odoo/odoo#230736, the function now includes in its count the leaves that have no calendar, regardless of the company. This commit fixes this by grouping them by company as well, and including that count. 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#276472
Original PR description
Following odoo/odoo#230736, the function now includes in its count the leaves that have no calendar, regardless of the company. This commit fixes this by grouping them by company as well, and including that count. 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#276472
A POS session could not be closed if there were draft orders planned for later the same day. The backend check was only filtering out orders with a date strictly in the future, ignoring the time part for same-day orders. task-id: 6000698 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#269093 Forward-Port-Of: odoo/odoo#251935
Original PR description
A POS session could not be closed if there were draft orders planned for later the same day. The backend check was only filtering out orders with a date strictly in the future, ignoring the time part for same-day orders. task-id: 6000698 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#269093 Forward-Port-Of: odoo/odoo#251935
Miscellaneous changes
### before ~1.4s <img width="1869" height="819" alt="image" src="https://github.com/user-attachments/assets/168e3831-929b-43fd-9aa1-ea5bfb22d3fe" /> ### after ~570ms <img width="1862" height="860" alt="image" src="https://github.com/user-attachments/assets/ea907064-fe12-4711-9707-67926f05cedf" /> See commit messages --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274360
Original PR description
### before ~1.4s <img width="1869" height="819" alt="image" src="https://github.com/user-attachments/assets/168e3831-929b-43fd-9aa1-ea5bfb22d3fe" /> ### after ~570ms <img width="1862" height="860" alt="image" src="https://github.com/user-attachments/assets/ea907064-fe12-4711-9707-67926f05cedf" /> See commit messages --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274360
12 changes
Resolved issues and error corrections
Once the cron is called to update current_version_id, the new employee calendar is applied to the previous version as well, due to the inverse on resource.resource def _inverse_calendar_id(self): for resource in self: if resource.calendar_id != resource.employee_id.resource_calendar_id: resource.employee_id.resource_calendar_id = resource.calendar_id All that because the introduced piece of code was called before super if 'current_versi
Original PR description
Once the cron is called to update current_version_id, the new employee calendar is applied to the previous version as well, due to the inverse on resource.resource
def _inverse_calendar_id(self):
for resource in self:
if resource.calendar_id != resource.employee_id.resource_calendar_id:
resource.employee_id.resource_calendar_id = resource.calendar_id
All that because the introduced piece of code was called before super
if 'current_version_id' in vals:
new_version = self.env['hr.version'].browse(vals.get('current_version_id'))
self.resource_id.calendar_id = new_version.resource_calendar_id
And this the inverse method was called on the previous version (not yet updated), not the new one.
Forward-Port-Of: odoo/odoo#279048## Problem When a `web_read_group` call is made with some condition on the active field, the active test is bypassed by adding `['active', 'in', [True, False]]` to the domain. This will cause a search to fail if the model's active field is not called `active` (like in a studio model). ## Solution We will change the domain to `[self._active_name, 'in', [True, False]]` to properly handle customizations. ## Steps to replicate (Runbot v19) 1. Create a new model with Studio - enable Pipeline
Original PR description
## Problem When a `web_read_group` call is made with some condition on the active field, the active test is bypassed by adding `['active', 'in', [True, False]]` to the domain. This will cause a search to fail if the model's active field is not called `active` (like in a studio model). ## Solution We will change the domain to `[self._active_name, 'in', [True, False]]` to properly handle customizations. ## Steps to replicate (Runbot v19) 1. Create a new model with Studio - enable Pipeline and Archiving 2. Open the kanban view and add 'Archived' to the filter 3. Traceback opw-6403422 Forward-Port-Of: odoo/odoo#277908 Forward-Port-Of: odoo/odoo#277666
When the shop sidebar categories are enabled with collapsed categories, subcategory names could wrap unexpectedly at 100% zoom or lower, even when there was enough available space. Steps to reproduce: - Open the Shop page and click Edit - Go to the Style tab - Set Content Width to Full - Enable the Categories sidebar - Enable Collapse Category This issue caused sidebar subcategory labels to wrap only at lower zoom levels, while higher zoom levels displayed them correctly. Add CSS
Original PR description
When the shop sidebar categories are enabled with collapsed categories, subcategory names could wrap unexpectedly at 100% zoom or lower, even when there was enough available space. Steps to reproduce: - Open the Shop page and click Edit - Go to the Style tab - Set Content Width to Full - Enable the Categories sidebar - Enable Collapse Category This issue caused sidebar subcategory labels to wrap only at lower zoom levels, while higher zoom levels displayed them correctly. Add CSS rules to prevent category names in the sidebar from wrapping. opw-6296804 Forward-Port-Of: odoo/odoo#275279
`_get_belgian_cocontractant_note()` resolves the co-contractant fiscal position through chart_template.ref(), which uses env.company. The "Send invoices automatically" cron runs as the inactive OdooBot user, so env.company is OdooBot's default company, not the invoice's. That company can differ from the invoice's and even be archived, in which case ref() raises "IndexError: tuple index out of range" (parent_ids is empty for an archived company) Steps to reproduce: - Set the main company to a
Original PR description
`_get_belgian_cocontractant_note()` resolves the co-contractant fiscal position through chart_template.ref(), which uses env.company. The "Send invoices automatically" cron runs as the inactive OdooBot user, so env.company is OdooBot's default company, not the invoice's. That company can differ from the invoice's and even be archived, in which case ref() raises "IndexError: tuple index out of range" (parent_ids is empty for an archived company) Steps to reproduce: - Set the main company to a non-Belgian company, and invoice from another active Belgian company. - Move every active user off the main company and archive it - Send a Belgian 0% invoice through the cron. => IndexError: tuple index out of range in chart_template.ref opw-6398778 Forward-Port-Of: odoo/odoo#278666 Forward-Port-Of: odoo/odoo#278326
Following odoo/odoo#230736, the function now includes in its count the leaves that have no calendar, regardless of the company. This commit fixes this by grouping them by company as well, and including that count. 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#276472
Original PR description
Following odoo/odoo#230736, the function now includes in its count the leaves that have no calendar, regardless of the company. This commit fixes this by grouping them by company as well, and including that count. 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#276472
When an order/invoice is fully discounted by a global discount, its base and tax amounts are sums of values each already rounded to the currency precision, so their sum is only a sub-unit floating point residue (~1e-6) instead of a clean zero. `_get_tax_totals_summary` fed that raw sum straight to the cash rounding. With a 'UP' (or 'DOWN') rounding method the residue was inflated into a full rounding step, e.g. a 0.01 total to pay on an otherwise empty document. opw-6402143 --- I confi
Original PR description
When an order/invoice is fully discounted by a global discount, its base and tax amounts are sums of values each already rounded to the currency precision, so their sum is only a sub-unit floating point residue (~1e-6) instead of a clean zero. `_get_tax_totals_summary` fed that raw sum straight to the cash rounding. With a 'UP' (or 'DOWN') rounding method the residue was inflated into a full rounding step, e.g. a 0.01 total to pay on an otherwise empty document. opw-6402143 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278291
When `cash_rounding` is enabled on a POS config but `rounding_method` is not set,`get_tax_totals_summary` is called with undefined (instead of null). Fix: ensure the `rounding_method` is set when `cash_rounding` is enabled, otherwise pass null to `get_tax_totals_summary`. task-id: 6388234 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278144 Forward-Port-Of: odoo/odoo#276914
Original PR description
When `cash_rounding` is enabled on a POS config but `rounding_method` is not set,`get_tax_totals_summary` is called with undefined (instead of null). Fix: ensure the `rounding_method` is set when `cash_rounding` is enabled, otherwise pass null to `get_tax_totals_summary`. task-id: 6388234 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278144 Forward-Port-Of: odoo/odoo#276914
When receiving a Peppol/UBL XML file containing an embedded PDF via an email alias, the PDF is not extracted and attached to the resulting vendor bill. Steps to reproduce: - Set up a BE Company - Configure an incoming mail server - Set up an email alias for the Vendor Bill journal - Receive a Peppol XML with embedded PDF via alias - Check the created Bill Issue: PDF has not been extracted from the xml This occurs because the received xml is set as main attachment for the record a
Original PR description
When receiving a Peppol/UBL XML file containing an embedded PDF via an email alias, the PDF is not extracted and attached to the resulting vendor bill. Steps to reproduce: - Set up a BE Company - Configure an incoming mail server - Set up an email alias for the Vendor Bill journal - Receive a Peppol XML with embedded PDF via alias - Check the created Bill Issue: PDF has not been extracted from the xml This occurs because the received xml is set as main attachment for the record and in this case we skip extraction opw-6075250 Forward-Port-Of: odoo/odoo#278806 Forward-Port-Of: odoo/odoo#262047
### 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#276306
Issue ----- International deliveries for fractions of items (eg 500g of a product sold by kg) are rejected by Sendcloud. Steps to reproduce ----- - Setup Sendcloud - Fedex international - Create a product - weight: 1kg - valid hs code - Create a contact (outside EU if the company is in EU) - Deliver 0.5 of the product to the contact > Error "... parcel not returned from Sendcloud" Cause ----- Sendcloud returns he folloing error: > "The total weight for declared items e
Original PR description
Issue ----- International deliveries for fractions of items (eg 500g of a product sold by kg) are rejected by Sendcloud. Steps to reproduce ----- - Setup Sendcloud - Fedex international - Create a…
Issue ----- International deliveries for fractions of items (eg 500g of a product sold by kg) are rejected by Sendcloud. Steps to reproduce ----- - Setup Sendcloud - Fedex international - Create a product - weight: 1kg - valid hs code - Create a contact (outside EU if the company is in EU) - Deliver 0.5 of the product to the contact > Error "... parcel not returned from Sendcloud" Cause ----- Sendcloud returns he folloing error: > "The total weight for declared items exceeds the total weight set for the shipment." This is because the `weight` set on the shipment https://github.com/odoo/enterprise/blob/99a13453cac8a7a4677cef3df8896329c90c9e99/delivery_sendcloud/models/sendcloud_service.py#L449-L464 corresponds to the weight of the package, whereas the weight set on the description of the product in `parcel_items` corresponds to the weight of one "full" unit of the product. https://github.com/odoo/enterprise/blob/99a13453cac8a7a4677cef3df8896329c90c9e99/delivery_sendcloud/models/sendcloud_service.py#L327-L335 We cannot change the quantity in `parcel_items` to match the actual delivered one because the field should be an integer. https://sendcloud.dev/api/v2/parcels/create-a-parcel-or-parcels#body-one-of-0-parcel-parcel-items-items-quantity The price is also off, because it gets taken from the `move_line`, so it reflects the price of the actual quantity and not a "full" item. https://github.com/odoo/odoo/blob/208a8a6a5adb8ec1f2710453c2ee3b54c55a9f1e/addons/stock_delivery/models/delivery_carrier.py#L235 Note that this issue is common to **all UoM types**. Solution ----- Since we cannot change the quantity, we can instead adapt the description and weight sent in `parcel_items`. For example, sending 300g of sugar, we would send - description: "Sugar (0.3 kg)" - weight: "0.300" ----- Ticket: opw-6346330 Forward-Port-Of: odoo/odoo#277440
e39bf6c6ab31e57d472a552cb9b902496e6323ae introduced a blacklist to email sending, to filter out "alias emails" (catchall...) & the root partner email (odoobot) from being sent certain emails, such as mailings. By default, odoobot email is odoobot@example.com. However, there are cases where users will have a legitimate partner that matches the odoobot email; an example of this is saas config, which automatically changes the odoobot email to the admin email set on database spin-up. This
Original PR description
e39bf6c6ab31e57d472a552cb9b902496e6323ae introduced a blacklist to email sending, to filter out "alias emails" (catchall...) & the root partner email (odoobot) from being sent certain emails, such as mailings. By default, odoobot email is odoobot@example.com. However, there are cases where users will have a legitimate partner that matches the odoobot email; an example of this is saas config, which automatically changes the odoobot email to the admin email set on database spin-up. This prevents the database admin from receiving their own mailings. To fix this, the root partner email is now only added to the blacklist if no active partner has the same email. Steps to reproduce: - Add a mailing contact with the same email as the root partner - Send a mailing to that mailing contact task-4893615 Forward-Port-Of: odoo/odoo#278717 Forward-Port-Of: odoo/odoo#264112
Some partners were registered on Peppol with EAS 9925 (Belgian VAT) but have since moved to 0208. They became unreachable via Peppol because we never check if they exist on the network with EAS 0208, which makes their status `not_valid`. This fix forces the re-checking of the status with EAS 0208 for partners having EAS 9925 and a `not_valid` status. task-6296017 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277072
Original PR description
Some partners were registered on Peppol with EAS 9925 (Belgian VAT) but have since moved to 0208. They became unreachable via Peppol because we never check if they exist on the network with EAS 0208, which makes their status `not_valid`. This fix forces the re-checking of the status with EAS 0208 for partners having EAS 9925 and a `not_valid` status. task-6296017 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#277072 Forward-Port-Of: odoo/odoo#270742
1 change
Resolved issues and error corrections
Issue caused because of https://github.com/odoo/odoo/commit/619d8ce9f31349ed06b11ead4988a4a1d9ca6bdd Steps to reproduce- Create db with demo and install l10n_in Create a new company for India (other than IN Company) Go to Settings -> Accounting/Invoice Tab -> Enable Ewaybill traceback ```py Traceback (most recent call last): File "/home/odoo/odoo18/community/odoo/orm/models.py", line 5385, in ensure_one _id, = self._ids ^^^^ ValueError: not enough values to unpack (expected
Original PR description
Issue caused because of https://github.com/odoo/odoo/commit/619d8ce9f31349ed06b11ead4988a4a1d9ca6bdd Steps to reproduce- Create db with demo and install l10n_in Create a new company for India (other…
Issue caused because of https://github.com/odoo/odoo/commit/619d8ce9f31349ed06b11ead4988a4a1d9ca6bdd Steps to reproduce-
Create db with demo and install l10n_in
Create a new company for India (other than IN Company) Go to Settings -> Accounting/Invoice Tab -> Enable Ewaybill
traceback
```py
Traceback (most recent call last):
File "/home/odoo/odoo18/community/odoo/orm/models.py", line 5385, in ensure_one
_id, = self._ids
^^^^
ValueError: not enough values to unpack (expected 1, got 0)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/odoo/odoo18/community/odoo/http/router.py", line 273, in __call__
response = serve_db(request)
^^^^^^^^^^^^^^^^^
File "/home/odoo/odoo18/community/odoo/http/router.py", line 380, in serve_db
registry = Registry(request.db)
^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/odoo18/community/odoo/orm/registry.py", line 105, in __new__
return cls.new(db_name)
^^^^^^^^^^^^^^^^
File "/home/odoo/odoo18/community/odoo/tools/func.py", line 67, in locked
return func(inst, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/odoo18/community/odoo/orm/registry.py", line 217, in new
cr.rollback()
File "/home/odoo/odoo18/community/odoo/sql_db.py", line 568, in rollback
with rollbacking:
File "/home/odoo/.pyenv/versions/3.12.0/lib/python3.12/contextlib.py", line 144, in __exit__
next(self.gen)
File "/home/odoo/odoo18/community/odoo/orm/environments.py", line 1004, in rollbacking
self.restore_state()
File "/home/odoo/odoo18/community/odoo/orm/environments.py", line 1067, in restore_state
self.reset()
File "/home/odoo/odoo18/community/odoo/orm/environments.py", line 912, in reset
self._reset_registry_change()
File "/home/odoo/odoo18/community/odoo/orm/environments.py", line 832, in _reset_registry_change
registry._setup_models__(cr)
File "/home/odoo/odoo18/community/odoo/tools/func.py", line 67, in locked
return func(inst, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/odoo18/community/odoo/orm/registry.py", line 422, in _setup_models__
env.invalidate_all()
File "/home/odoo/odoo18/community/odoo/orm/environments.py", line 395, in invalidate_all
self.flush_all()
File "/home/odoo/odoo18/community/odoo/orm/environments.py", line 413, in flush_all
self._recompute_all()
File "/home/odoo/odoo18/community/odoo/orm/environments.py", line 406, in _recompute_all
self[field.model_name]._recompute_field(field)
File "/home/odoo/odoo18/community/odoo/orm/models.py", line 6462, in _recompute_field
field.recompute(records)
File "/home/odoo/odoo18/community/odoo/orm/fields.py", line 2042, in recompute
apply_except_missing(self.compute_value, recs)
File "/home/odoo/odoo18/community/odoo/orm/fields.py", line 2012, in apply_except_missing
func(records)
File "/home/odoo/odoo18/community/odoo/orm/fields.py", line 2066, in compute_value
records._compute_field_value(self)
File "/home/odoo/odoo18/community/addons/mail/models/mail_thread.py", line 498, in _compute_field_value
return super()._compute_field_value(field)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/odoo18/community/odoo/orm/models.py", line 4387, in _compute_field_value
determine(field.compute, self)
File "/home/odoo/odoo18/community/odoo/orm/fields.py", line 82, in determine
return needle(*args)
^^^^^^^^^^^^^
File "/home/odoo/odoo18/community/addons/l10n_in_ewaybill/models/l10n_in_ewaybill.py", line 228, in _compute_document_partners_details
seller_buyer_details = ewaybill._get_seller_buyer_details()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/odoo18/community/addons/l10n_in_ewaybill/models/l10n_in_ewaybill.py", line 185, in _get_seller_buyer_details
return move._get_l10n_in_seller_buyer_party()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/odoo18/community/addons/l10n_in/models/account_invoice.py", line 629, in _get_l10n_in_seller_buyer_party
self.ensure_one()
File "/home/odoo/odoo18/community/odoo/orm/models.py", line 5388, in ensure_one
raise ValueError("Expected singleton: %s" % self)
ValueError: Expected singleton: account.move()
```
In this commit, we resolve the above traceback
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr4 changes
Resolved issues and error corrections
**Current behavior before PR:** Steps to reproduce the issue: - Go to a To-Do. - Insert a heading, write something. - Insert a table of content. - Make sure that editable is not scrollable. Clicking on heading label inside toc leads to traceback. The issue occurs after merging commit [1]. When editable is not scrollable then `closestScrollableY` returns null which leads to traceback. **Desired behavior after PR:** If editable is not scrollable then clicking on heading inside to
Original PR description
**Current behavior before PR:** Steps to reproduce the issue: - Go to a To-Do. - Insert a heading, write something. - Insert a table of content. - Make sure that editable is not scrollable. Clicking on heading label inside toc leads to traceback. The issue occurs after merging commit [1]. When editable is not scrollable then `closestScrollableY` returns null which leads to traceback. **Desired behavior after PR:** If editable is not scrollable then clicking on heading inside toc should hightlight the corresponding heading without traceback. [1]: https://github.com/odoo/odoo/commit/f5cf8565e7d09edd3a29fd95537381fb70d75785 task-6405894 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Steps to reproduce --- 1. Confirm a purchase order and receive it a few days later. 2. Open Purchase, Reporting, Purchase and add the "Effective Days To Arrival" measure. Observed: the value is counted from the line's scheduled date instead of the order date, and can even be negative when the scheduled date precedes the confirmation date. Issue --- The metric is meant to be the effective lead time, the number of days between the order confirmation and the actual receipt, falling back
Original PR description
Steps to reproduce --- 1. Confirm a purchase order and receive it a few days later. 2. Open Purchase, Reporting, Purchase and add the "Effective Days To Arrival" measure. Observed: the value is…
Steps to reproduce --- 1. Confirm a purchase order and receive it a few days later. 2. Open Purchase, Reporting, Purchase and add the "Effective Days To Arrival" measure. Observed: the value is counted from the line's scheduled date instead of the order date, and can even be negative when the scheduled date precedes the confirmation date. Issue --- The metric is meant to be the effective lead time, the number of days between the order confirmation and the actual receipt, falling back to the planned "days to receive" when nothing has been received yet according to [task](https://www.odoo.com/odoo/project/809/tasks/3691573). The query instead computes age(date_planned, COALESCE(date_done, date_order)), so once a receipt exists it returns date_planned - date_done (the gap between the scheduled date and the receipt) rather than date_done - date_order. https://github.com/odoo/odoo/blob/c06be48ce7277a667719fd756e0a1f63e91cda27/addons/purchase_stock/report/purchase_report.py#L20-L28 opw-6226523 Forward-Port-Of: odoo/odoo#268843
While preloading chart template data, if an account already exists in the db but has `active=False`, it is not found because archived records are excluded from the [`_search`]. As a result, the load attempts to create a new account. During creation, the Python constraint [`_ensure_code_is_unique`] searches with `active_test=False`, finds the archived account with the same code, and raises a ValidationError: ```py File "/home/odoo/src/odoo/saas-19.2/addons/account/models/chart_template.py"
Original PR description
While preloading chart template data, if an account already exists in the db but has `active=False`, it is not found because archived records are excluded from the [`_search`]. As a result, the load…
While preloading chart template data, if an account already exists in the db but has `active=False`, it is not found because archived records are excluded from the [`_search`].
As a result, the load attempts to create a new account. During creation, the Python constraint [`_ensure_code_is_unique`] searches with `active_test=False`, finds the archived account with the same code, and raises a ValidationError:
```py
File "/home/odoo/src/odoo/saas-19.2/addons/account/models/chart_template.py", line 735, in _load_data
'noupdate': True,
^
File "/home/odoo/src/odoo/saas-19.2/odoo/orm/models.py", line 4519, in _load_records
records = self._load_records_create([data['values'] for data in to_create])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/saas-19.2/odoo/orm/models.py", line 4426, in _load_records_create
records = self.create(vals_list)
^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/saas-19.2/odoo/orm/decorators.py", line 363, in create
return method(self, vals_list)
^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/saas-19.2/addons/account/models/account_account.py", line 1057, in create
records._ensure_code_is_unique()
File "/home/odoo/src/odoo/saas-19.2/addons/account/models/account_account.py", line 1135, in _ensure_code_is_unique
raise ValidationError(
odoo.exceptions.ValidationError: Account codes must be unique. You can't create accounts with these duplicate codes: 1.1.1.02.003, 1.1.1.02.004
```
Steps to reproduce:
- In a `v19.0` database, install `l10n_ar` with demo data.
- The accounts with codes `1.1.1.02.003` and `1.1.1.02.004` are created by [`_create_outstanding_accounts`].
- Archive those accounts and upgrade to `v19.2`.
- During the upgrade, [`_get_latam_check_outstanding_account_account`] attempts to create new accounts with the same codes, triggering the duplicate code validation.
tbg-2840
[`_search`]: https://github.com/odoo/odoo/blob/619d8ce9f31349ed06b11ead4988a4a1d9ca6bdd/addons/account/models/chart_template.py#L438
[`_ensure_code_is_unique`]: https://github.com/odoo/odoo/blob/19.0/addons/account/models/account_account.py#L1133
[`_create_outstanding_accounts`]: https://github.com/odoo/odoo/blob/06a46b083fde5688d71c5602553316c9e7160b6a/addons/account/models/chart_template.py#L925C9-L949
[`_get_latam_check_outstanding_account_account`]: https://github.com/odoo/odoo/blob/saas-19.2/addons/l10n_latam_check/models/account_chart_template.py#L60-L76
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prSteps to reproduce: - set the "Product Price" decimal precision to 3 - create two products with a price of 42.609 and a 15% excluded tax - create an automatic promotion granting a 20.4% discount on these specific products - in the PoS, sell both products: the reward line shows -20.00 and the order total 78.00 - pay 100.00 in cash and validate The synced order total becomes 78.01 while the customer paid 78.00. The discount reward line is created in the frontend with an unrounded price
Original PR description
Steps to reproduce: - set the "Product Price" decimal precision to 3 - create two products with a price of 42.609 and a 15% excluded tax - create an automatic promotion granting a 20.4% discount on…
Steps to reproduce: - set the "Product Price" decimal precision to 3 - create two products with a price of 42.609 and a 15% excluded tax - create an automatic promotion granting a 20.4% discount on these specific products - in the PoS, sell both products: the reward line shows -20.00 and the order total 78.00 - pay 100.00 in cash and validate The synced order total becomes 78.01 while the customer paid 78.00. The discount reward line is created in the frontend with an unrounded price unit: -(85.22 * 20.4%) = -17.384879999999995. The frontend computes taxes on the price unit rounded to the "Product Price" precision (see `get_unit_price()`): -17.385 -> -17.39 - 2.61 = -20.00 tax included, hence the 78.00 total displayed and paid. However, the raw value is what is sent to the server and stored as-is (`pos.order.line.price_unit` is declared with `digits=0`). Whenever the backend recomputes the amounts from the lines - e.g. when a cash change makes `_process_payment_lines()` call `_compute_prices()` - the taxes are computed on the raw value: -17.38 - 2.61 = -19.99, and the order total drifts to 78.01. Round the reward line price unit to the "Product Price" precision when creating it, as `_getRewardLineValuesProduct()` already does, so the stored value is the one the frontend computed its totals with. opw-6322031 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275961
1 change
Resolved issues and error corrections
On Firefox, history.replaceState() enforces a strict size limit (~640KB) on the state object. Customers with a large number of folders in the Documents module cause the serialized history state to exceed this limit, resulting in an uncaught NS_ERROR_ILLEGAL_VALUE that breaks all navigation on Firefox. To fix this, we wrap history.pushState() and history.replaceState() calls in doPush() with a try/catch that catches NS_ERROR_ILLEGAL_VALUE and falls back to storing null state. opw-6182687
Original PR description
On Firefox, history.replaceState() enforces a strict size limit (~640KB) on the state object. Customers with a large number of folders in the Documents module cause the serialized history state to exceed this limit, resulting in an uncaught NS_ERROR_ILLEGAL_VALUE that breaks all navigation on Firefox. To fix this, we wrap history.pushState() and history.replaceState() calls in doPush() with a try/catch that catches NS_ERROR_ILLEGAL_VALUE and falls back to storing null state. opw-6182687