Tuesday, August 25, 2026
68 changes · saas-19.4
Resolved issues and error corrections
Point of Sale preparation tickets can now be reprinted correctly when an order includes combo products. This prevents silent printing failures in restaurants or retail setups that use preparation printers for combo items.
Original PR description
Steps to reproduce: --- - Configure a Point of Sale with a preparation printer whose product categories contain the products of a combo. - Add the combo to an order and send it to preparation. - Try to reprint the order. Issue: --- - Nothing is printed for orders containing a combo, without any error being shown. Fix: --- - Store the combo children of a preparation change as plain ids and match the printer categories on those ids. task-6472281 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fix ensures discounts are only applied once when calculating withholding tax amounts. Businesses using withholding taxes with discounted invoice lines should now see more accurate withholding totals, reducing accounting discrepancies.
Original PR description
When calculating tax details for `withholding_total_amount_currency`, the discount was already applied to `price_unit` before passing it to `_add_tax_details_in_base_line`. However, `_add_tax_details_in_base_line` already applies the discount itself. As a result, the discount was applied twice, causing the withholding amount to be calculated incorrectly. In this commit, remove the initial discount calculation and pass the original price_unit so that the discount is applied only once. ref- https://github.com/odoo/odoo/blob/master/addons/account/models/account_tax.py#L1804C9-L1804C34 task-6471414
This fix improves how product names and descriptions appear on accounting lines. Descriptions now stay italic even when text wraps in narrow columns, preventing product names from being styled incorrectly and making entries easier to read.
Original PR description
This commit removes the CSS hack used to make the description italic when a product is present in an AML. Instead, the product name and description are rendered separately using two spans in the readonly state. The previous `:first-line` approach did not handle line wrapping correctly: when the column was too narrow, part of the product name could wrap onto the next line and incorrectly appear italic. Rendering the two parts separately avoids this issue. Before | After -- | -- <img width="414" height="192" alt="image" src="https://github.com/user-attachments/assets/a178a35c-6d55-4982-a9c3-2fe727c626cc" /> | <img width="399" height="198" alt="image" src="https://github.com/user-attachments/assets/4716f93a-6d47-4631-a982-db43d9d38ef0" /> --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fixes an issue where employee searches could fail or return incorrect results for users without access to private employee details. It helps keep HR searches reliable while maintaining the intended access restrictions.
Original PR description
The hack to search fields as a user that has no access to private employee data and searching on the `current_version_id` instead of the provided field since we force to wrap searchable fields domains in a Query in odoo/odoo#280373. The hack did not support usage of the 'any!' operator on `current_version_id` leading to a query like: "hr_employee.id in (select id from hr_version ...)". task-6468820 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284271 Forward-Port-Of: odoo/odoo#283811
This fix prevents an error when opening the sales product configurator in debug mode for products with optional custom attribute values. Empty custom values are now handled correctly, so users and testers can configure these products without encountering a crash.
Original PR description
This commit prevents a traceback when opening the product configurator in debug mode. Prop validation only happens in debug mode, which exposed an issue with products that allow entering custom attribute values (e.g. Acoustic Bloc Screen). When a custom value is left empty, it is read as `false` when custom attributes are retrieved from the frontend. As a result, the `custom_value` key in the `customPtavs` prop passed to the product configurator contains a boolean, whereas the prop expects a string. This commit ensures that an empty string is passed instead of `false` when opening the configurator for a line with an empty custom attribute value. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Edited chatter messages now keep contact mentions linked correctly when contact names or IDs overlap. This prevents mentions from breaking or pointing to the wrong contact, improving reliability in everyday communication.
Original PR description
# Introduction This PR fixes broken mention links linked to the fact that we replace strings without paying attention to the fact that some strings may contain others that we want to replace later.…
# Introduction
This PR fixes broken mention links linked to the fact that we replace strings
without paying attention to the fact that some strings may contain others
that we want to replace later. This affects both id's and names of records.
See commit messages for more details.
# How to reproduce
- Create Contact A and then Contact B and either :
- Contact B's id need to contain Contact A's id (e.g. Contact B id = 12; Contact A id = 1)
- Contact B's name need to contain Contact A's name (e.g. Contact B name = ABC; Contact A name = AB)
- In a chatter create a message mentionning first Contact B and then Contact A
> Depending on the version, you might need to reload the page here
- Edit the message and save
# The issue
We see a broken mention in the chatter
# Cause
When saving an edited message, we give the raw body of the message (without the mention links) and the mentionend partners to `generateMentionsLinks` : https://github.com/odoo/odoo/blob/f9f605b1783d252d5e005bec50a2a72dd4ae0e13/addons/mail/static/src/utils/common/format.js#L152
This method's purpose is to replace the text links ("@Contact A") with actual html links. It does so by enumerating each partner given as an argument and replace the text mention with a placeholder :
https://github.com/odoo/odoo/blob/f9f605b1783d252d5e005bec50a2a72dd4ae0e13/addons/mail/static/src/utils/common/format.js#L158
It will then replace the placeholders with actual links : https://github.com/odoo/odoo/blob/f9f605b1783d252d5e005bec50a2a72dd4ae0e13/addons/mail/static/src/utils/common/format.js#L208-L218
The issue is that in both of those steps, we can try to replace a string that is contained
in another string we want to replace.
For exemple :
"string123 some text string12"
If we try to replace "string12" first, then we will select the wrong string :
"[string12]3 some text string12".
opw-6313748
Forward-Port-Of: odoo/odoo#283817
Forward-Port-Of: odoo/odoo#272549This change updates website shop testing so inactive products are excluded during test runs. It helps prevent false test failures without changing what customers can see in the online store.
Original PR description
Description of the issue/feature this PR addresses: Addresses an issue causing test failures by ensuring that [inactive products](https://github.com/odoo-dev/odoo/blob/dbc917ddc263a330ff70f5edec716ccafe88d7a6/addons/website_sale/tests/test_product_filters.py#L93-L99) are filtered out rather than leaking from the environment into the test execution. I have verified that this issue does not allow [inactive records to leak to customers](https://www.odoo.com/mail/message/1151343506). runbot-242426 Forward-Port-Of: odoo/odoo#283973
Fixed an issue where stock pickings created from confirmed purchase requests could lose the project selected on the purchase document. This helps teams keep project-related purchasing and inventory movements correctly connected for tracking and reporting.
Original PR description
## Steps to reproduce: - Install project_purchase_stock and sale_project_stock - Create a RFQ and link it to a project - Confirm the RFQ - Check the linked stock picking - Notice the project didn't…
## Steps to reproduce: - Install project_purchase_stock and sale_project_stock - Create a RFQ and link it to a project - Confirm the RFQ - Check the linked stock picking - Notice the project didn't auto-populate from the PO to the stock picking ## Cause: During preparing the picking creation values. In the override chain for `_get_new_picking_values` we have two modules that adds `project_id` value https://github.com/odoo/odoo/blob/658018684d781fef8bf77a77f1e050d1eb16937c/addons/sale_project_stock/models/stock_move.py#L60-L64 https://github.com/odoo/odoo/blob/658018684d781fef8bf77a77f1e050d1eb16937c/addons/project_purchase_stock/models/stock_move.py#L9-L13 And since the one in sale_project_stock is called first so when we are returning the values it will overwrite the project_id value that has been added in project_purchase_stock ## Fix: Make sure that there are not value for project_id before setting another value to avoid overwriting the value the fix is a backport of part of this commit https://github.com/odoo/odoo/commit/b1caeacc3fa73b71de7254f1aa8334154f6db8cc opw-6459561 Forward-Port-Of: odoo/odoo#282777
This update fixes automated tests for restaurant appointments in Point of Sale after a storage-clearing behavior changed during data reloads. It keeps production behavior unchanged while ensuring test runs can complete reliably without losing their saved test state.
Original PR description
A recent PR in the community repository introduced a full clear of both `localStorage` and `sessionStorage` when reloading POS data. While this is the intended behavior in production, it breaks the test framework. This commit mocks the `clear` methods directly within the tour steps right before the reload action. This ensures the test survives the page reload and keeps its state, without polluting the core production code with test-specific logic. task-6456447 Forward-Port-Of: odoo/enterprise#128692 Forward-Port-Of: odoo/enterprise#128091
This fix prevents an error that could block customers from generating batch payments. It corrects a broken internal call introduced during a previous code update, helping payment processing complete reliably.
Original PR description
The aim of this commit is to allow customer to make their batch payment without facing a Traceback. Context: odoo/enterprise@35f5341b9b44cc16eaea311295a064189dd802cb introduced bug during a badly…
The aim of this commit is to allow customer to make their batch payment
without facing a Traceback.
Context:
odoo/enterprise@35f5341b9b44cc16eaea311295a064189dd802cb introduced bug
during a badly handled forward port.
The method was removed in saas-18.3 in favor of a function. The forward-port
was half handled and now surfaces to Odoo's own production.
Generating a batch payment could generates the following Traceback:
```py
File "/home/odoo/src/enterprise/saas-19.3/account_iso20022/models/account_journal_sepa_ct.py", line 69, in _get_PstlAdr
return super()._get_PstlAdr(partner_id, payment_method_code)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/enterprise/saas-19.3/account_iso20022/models/account_journal.py", line 501, in _get_PstlAdr
CtrySubDvsn.text = self._sepa_sanitize_communication(partner_address['state'][:35])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'account.journal' object has no attribute '_sepa_sanitize_communication'
```
Task-id: None (internal issue)
Forward-Port-Of: odoo/enterprise#129084
Forward-Port-Of: odoo/enterprise#129006Archiving or deleting one user no longer removes their shared contact from restricted chat channels if another active user for that contact still qualifies. This prevents people from unexpectedly losing access to relevant discussions when accounts are cleaned up.
Original PR description
Before this commit, archiving or deleting a user removed its partner from every group restricted channel, even when another user of that partner was still active and in the group the channel requires. This happens because the members to unsubscribe are searched on partner_id alone, so the search cannot tell whether the partner keeps another user. This commit fixes the issue by unsubscribing a partner only when none of its remaining users has the group the channel requires. Forward-Port-Of: odoo/odoo#283933 Forward-Port-Of: odoo/odoo#283807
Odoo now keeps tax usage indicators up to date when related accounting, expense, purchase, or point-of-sale records are created, changed, or removed. This helps prevent outdated tax information from appearing in configuration screens and reduces the risk of incorrect tax setup decisions.
Original PR description
Currently, `is_used` is computed using queries on `account.move.line`, `account.reconcile.model.line`, etc. As a result, it has no depends and is not automatically updated when records in either model are created, modified, or deleted. This commit reverse M2M fields for respective models and use it as dependency to `_compute_is_used`. It also adds a missing dependency of `is_used` to `_compute_repartition_lines_str`. Forward-Port-Of: odoo/odoo#283406
When someone is mentioned, Odoo now selects an active user account for that person instead of potentially choosing an archived account. This helps ensure mention notifications appear in the intended recipient's inbox, reducing missed internal communication.
Original PR description
Before this commit, mentioning a partner that has an archived user sent the inbox notification to that archived user, so the mentioned person never saw the mention. This happens because the query picking the user of a recipient joins res_users without filtering on active, and keeps one row per partner with DISTINCT ON and no ORDER BY, so which row survives is arbitrary. One solution could have been to keep every active user of the partner, which is what we want as each of them has its own notification type, but a notification is stored per partner, so the type of a single user applies to all of them. Picking one user is a current limitation. This commit fixes the issue by taking the first active user of each partner in a lateral join, ordered as mail.followers._get_recipient_data already does: internal users first, then the lowest id. Forward-Port-Of: odoo/odoo#284214 Forward-Port-Of: odoo/odoo#283806
Inventory forecasts now correctly account for physical transfers entered with zero demand. This prevents past forecasted stock levels from being incorrectly reduced, improving accuracy in stock planning and reporting.
Original PR description
**Problem:** When creating a transfer that moves out a product with zero demand quantity, it will change the forecasted quantity of that product in the past. **Cause:** The query filtered out the stock move with zero demand quantity, which preventing the system from accounting for unplanned physical transfers when retroactively calculating past inventory balances **Steps to reproduce the issue:** 1. Create a stock picking with 0 demand quantity that moves a product from an internal location to a virtual location or production location. 2. The forecasted quantity of the product becomes negative in the past. **Fix:** Add another check in the query to include stock moves with zero demand quantity. **Notes:** Since the forecast report is made from a SQL view, this will require a -u to update the report. opw-6462883 Forward-Port-Of: odoo/odoo#284000 Forward-Port-Of: odoo/odoo#283577
Bullet points and lists in generated API documentation now use the proper styling. This makes documentation easier to read and reduces confusion for users consulting technical reference pages.
Original PR description
Bullet points and lists coming from the generated html by docutils were not properly styled. This commit fixes those cases. task-6484990
Fixes a website settings issue where clearing the cookie policy page could leave the cookie banner enabled without a linked policy page and hide the setting needed to restore it. The website now restores the default policy page when needed and prevents deleting a page that is still used as the cookie policy, helping keep cookie notices complete and manageable.
Original PR description
Steps to reproduce: - enable the cookies bar in the website settings and save - clear the "Cookie Policy Page" field and save The website was left without a cookie policy page while the cookies bar was still enabled. Since the settings view only displays the field when it has a value, it disappeared with no way to set it back, other than toggling the cookies bar off and on again. The default policy page was only restored when the `cookies_bar` flag itself changed, so a write clearing only `cookie_policy_id` slipped through. Restore the default page whenever the policy is emptied while the cookies bar remains enabled, so the field reappears with the default page after saving. task-6356766
Creating custom fields in the technical settings no longer fails when the AI fields feature sends an empty model value. This restores expected configuration workflows for administrators using AI-related field tools.
Original PR description
**Steps to reproduce** - Install `ai_fields` - In debug mode, go to Settings > Technical > Fields - Trying to create any field results in a `Validation Error` **Cause** Commit ebeab340264af42450b74a76d69fc284b600f94c introduced a check on `model` to prevent a mismatch. `ai_studio` adds the `model` as an invisible field to the form, sending a `False` value to the `create`. https://github.com/odoo/enterprise/blob/bafa674d287577a0f32e08af165dd9561b1667c0/ai_fields/views/ir_model_views.xml#L39 **Change** Ignore `model` if it is `False` opw-6463182
Belgian payroll reporting now allocates severance periods across the correct quarters by using the period from the actual departure date to the theoretical notice end date. The change also keeps valid manually entered departure dates instead of overwriting them, helping avoid incorrect declarations and rework.
Original PR description
- previously, the termination period was split from notice period start to actual departure date, ignoring the theoretical notice duration. Now, it correctly splits from actual departure date to theoretical end date, ensuring proper multi-quarter severance (Code 003) allocation. - Preserve departure_date if after dismissal_date, else default to theoretical notice end. previously the compute always overwrote any user input, ignoring manual adjustments task: 5407737 Forward-Port-Of: odoo/enterprise#112279
Point of Sale receipts now show the correct cash rounding line when a customer overpays, such as using a quick-add cash amount. This ensures receipts and payment totals remain clear and accurate for cash transactions with rounding rules.
Original PR description
**Steps to reproduce:** - Make a rounding method, Nearest and 0.05 of rounding - Make a product that costs $4.99, don't set a tax - Go to the PoS - Order the product - Before paying click the +10…
**Steps to reproduce:** - Make a rounding method, Nearest and 0.05 of rounding - Make a product that costs $4.99, don't set a tax - Go to the PoS - Order the product - Before paying click the +10 button, then pay - The rounding line is not present on the ticket **Why the fix:** When making a normal rounded purchase, by just clicking the "Cash" button, the rounding line will be displayed. This is because we do not try to apply the rounding if the rounding of the remaining is not equal to zero. https://github.com/odoo/odoo/blob/995629db3231de944710751c3184bf1b8b1355c7/addons/point_of_sale/static/src/app/models/accounting/pos_order_accounting.js#L118-L123 When we try to over pay, the remaining will be negative by the amount we overpay, so the amount will be set to zero, and the rounding will not be set. We now take the amount we overpay into account, and deduct it from the amount we paid to then correctly compute the remaining amount without having to deal with the amount overpaid. Some tests were not taking the rounding as it was not working correctly, so it has now been changed now that it works as it should. opw-6025807 Forward-Port-Of: odoo/odoo#283413 Forward-Port-Of: odoo/odoo#256117
The accounting dashboard now shows the full invoice or bill amount for documents marked "To Check" instead of only the unpaid balance. This makes the dashboard less misleading when documents have partial payments, because the whole document still needs review.
Original PR description
Currently, the "To Check" links on the dashboard display the residual amount of invoices and bills. Since the entire document needs to be checked regardless of partial payments, showing the remaining balance is misleading. This commit updates the `selects` list in `_get_to_check_payment_query` to use `amount_total` instead of `amount_residual`, ensuring the dashboard reflects the full value of the documents. Task-6478415 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284171
This fixes a problem that could cause user or record avatars to fail loading when an expected update date was missing. Business users should see more reliable avatar display in form and kanban views, with no workflow changes required.
Original PR description
Issue: The `Many2OneAvatarField` and `KanbanMany2OneAvatarField` templates were directly calling `value.write_date?.toMillis()`. Optional chaining does not handle the case where `write_date` is `false`, resulting in a `TypeError` because `toMillis()` is not available on a boolean value. Solution: Added a `uniqueId` getter in both `Many2OneAvatarField` and `KanbanMany2OneAvatarField` to safely handle a missing or false `write_date`. The getter calls `toMillis()` only when `write_date` is available and returns `undefined` otherwise. Both templates now use `uniqueId` for the avatar URL. opw-6464172 Forward-Port-Of: odoo/odoo#282659
This fix removes website editing options that were not useful on link tracking pages, including SEO optimization and related page menus. It helps prevent users from spending time configuring pages that do not contain meaningful visitor-facing content.
Original PR description
Since [this commit][1] you're able to optimize the link tracker page using "optimize seo." This makes no sense as it contains no useful content for visitors to the website. Access to the action is now disabled when the current page is the link tracking page. The page properties and link tracker menu items have also been removed for similar reasons. [1]: https://github.com/odoo/odoo/commit/ac55f2bb113ecf7c774fe6e96d28e716184a97d1 Task-6288891 Forward-Port-Of: odoo/odoo#283954 Forward-Port-Of: odoo/odoo#278132
This fixes an issue where selecting a Gboard word suggestion on mobile could place the suggested word incorrectly and only remove the last character of the original word. The editor now applies its keyboard-specific workaround more narrowly, improving mobile text entry reliability without affecting normal editing.
Original PR description
Before this commit: on mobile, when typing using Gboard and select a word suggestion will only delete the last character and put the new word at the beginning of the word to be replaced. This is because Gboard extends the selection to the text to be corrected, then deletes it, and inserts the corrected text. This flow falls in our previous fix for MS Swiftkey's delete backward, and wrongly uses cached old selection instead of using extended new selection from Gboard. After this commit: We strict the Swiftkey fix further, and only execute it when the cursor is at the beginning of the p element. Related commit: https://github.com/odoo/odoo/commit/822fd4e8fec7e114e6748dd8c9b4969f423fb290 task-6233756 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#278266
Clicking a followable field in the HTML editor now selects its display name by default instead of its technical ID. This makes dynamic placeholders more understandable for users while still allowing the ID to be selected when needed.
Original PR description
*: project Before this commit: when clicking a field having sub fields (canFollowRelationFor is true), we just return this field's id, which is not very useful in most cases. After this commit: We created subclass of DynamicPlaceholderPopover, EditorDynamicPlaceholderPopover, which uses EditorModelFieldSelectorPopover. We use the display name of the followable field by default and if the user really want the id, they may choose the id subfield. We also show the followable field's name as the default placeholder instead of "Display name". task-6265223 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283748 Forward-Port-Of: odoo/odoo#272129
This fixes invoice tax calculations when one tax changes the base amount used by a following tax on the same line. The affected tax totals now include the prior tax amount, helping ensure invoices and tax reports show accurate excluded totals.
Original PR description
**Steps to reproduce:** - Create a tax that affects the base of the subsequent ones - Create an invoice with this tax and another one on the same line **Issue:** In "_aggregate_base_line_tax_details", the tax amount from the first tax should be included in the following values of the second tax: - raw_total_excluded - raw_total_excluded_currency - target_total_excluded - target_total_excluded_currency - total_excluded - total_excluded_currency But it is not. opw-6235909 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284052 Forward-Port-Of: odoo/odoo#279335
This fix prevents Odoo from crashing when users navigate away from an HTML field while embedded content is still loading. It makes the editor safely cancel that loading when the original page area is no longer available, improving reliability without changing expected user workflows.
Original PR description
[Adoption of Owl v3.0.0-alpha.42] in Odoo codebase introduced timing differences when mounting a new App (sub-)root. This timing difference could cause a crash when mounting an embedded component in…
[Adoption of Owl v3.0.0-alpha.42] in Odoo codebase introduced timing differences when mounting a new App (sub-)root. This timing difference could cause a crash when mounting an embedded component in a html field, if the main App switched view away from the field where embedded components were waiting for their root to prepare, the root host wouldn't be in the DOM anymore, but the code would still try to mount these components. To avoid the issue, this commit makes use of `onBeforeComplete` to abort a pending mount if the owner instance (Component, editor plugin, ...) was destroyed before the mount could be initiated. This is the best strategy to silently ignore crashes caused by premature destruction of an ancestor while still keeping errors thrown when the host was removed from the DOM for other reasons that may need investigation. Aborting when the host is disconnected is the best strategy to avoid the crash entirely, but then we might miss those other reasons. [Adoption of Owl v3.0.0-alpha.42]: https://github.com/odoo/odoo/commit/acb95b28ab807b37ee86b381b555e38fae36ae93 runbot-944116
Message posting now checks and cleans submitted data according to the current user's permissions before accepting it. This helps prevent invalid or inappropriate message data from being processed, improving reliability and control in communication features.
Original PR description
This change sanitizes some post data before allowing the post, making sure the data received by `message_post` is clean based on the current user. part of task-6452761 Forward-Port-Of: odoo/odoo#284201 Forward-Port-Of: odoo/odoo#280894
Fixed a warning in the Indian localization so the related “View Journal Item(s)” link appears as intended. This helps users quickly open the relevant journal entries directly from the lower TCS tax warning.
Original PR description
The `lower_tcs_tax` warning was using the "actions" key instead of "action". As a result, the warning message was displayed correctly, but the "View Journal Item(s)" action link was not shown. Forward-Port-Of: odoo/odoo#284095
This fixes mailing recipient filtering so temporary wizard screens are no longer treated as valid mailing-enabled models. It helps prevent irrelevant internal setup records from appearing in mass mailing options, keeping campaign setup cleaner and less error-prone.
Original PR description
The search function ` _search_is_mailing_enabled` mistakenly used `model.is_transient()` (where the model is the `ir.model` record itself) to filter the transient models, which always returns `False` since `ir.model` is a regular persistent model. As a result, transient models (wizards) were never filtered out. This commit fixes it by using`self.env[model.model].is_transient()` to call `is_transient` on the actual model. Task-6458883 Forward-Port-Of: odoo/odoo#283781 Forward-Port-Of: odoo/odoo#282783
This fixes project margin reporting so company-paid expenses are not incorrectly shown as extra revenue. Business users will see more accurate actual margins on billable projects, avoiding overstated profitability when expenses are settled by the company.
Original PR description
Steps to reproduce --- 1. Install Sales (with Margins) and Project, and open a billable project linked to a sale order. 2. From the project's Expenses view, create an expense paid by the Company and…
Steps to reproduce --- 1. Install Sales (with Margins) and Project, and open a billable project linked to a sale order. 2. From the project's Expenses view, create an expense paid by the Company and post it. 3. Open the project's Actual Margins: the expense shows under Other Revenues as a positive amount. Issue --- Creating an expense from a project's Expenses view keeps `project_id` in the context until its journal entry is built. For a company-paid expense that entry is a payment, and `AccountMoveLine._compute_analytic_distribution` puts the project's analytic distribution on every line that is not receivable or payable, which also covers the Outstanding Payments liquidity line. An analytic amount is the opposite of the move line balance, so the negative liquidity balance becomes a positive analytic line, classified as Other Revenues, on top of the real cost already booked on the expense account. The receivable/payable filter from b6200026ecf1 narrowed the override introduced in ac1995ad6ddf but ignored the liquidity counterpart of a payment; since only profit and loss lines make up a project margin, restricting the distribution to `income` and `expense` accounts keeps the settlement line out of the report. https://github.com/odoo/odoo/blob/f037dead17eb6a74d1ea9c56b0861b285be17516/addons/sale_project/models/account_move_line.py#L10-L19 opw-6326551 Forward-Port-Of: odoo/odoo#283938 Forward-Port-Of: odoo/odoo#273273
This fix prevents subcontracted inventory movements from being counted as already reserved stock in outgoing forecasts. Businesses using subcontracting and make-to-order flows will see more reliable availability statuses, reducing the risk of planning production around components that have not actually been received or reserved.
Original PR description
### Steps to reproduce: - Enable Multi-Steps Routes, subcontracting and unarchive the MTO route - Create 3 products: Final Product (FP), Subcontracted Component (SB), Component (COMP) and put SB in…
### Steps to reproduce: - Enable Multi-Steps Routes, subcontracting and unarchive the MTO route - Create 3 products: Final Product (FP), Subcontracted Component (SB), Component (COMP) and put SB in MTO - Create a BOM for FP: 1 x SB - Create a subcontracted BOM for SB: 1 x COMP - Create and confirm an MO for 1 unit of FP > This generates a subcontracted MO for 1 unit of SB - Confrim the subcontracted PO and go back to the MO of FP #### > The component move forecast appears "Available" even if the SB unit is neither received nor 'pre-reserved' (the quantity of the move raw is still 0). ### Cause of the issue: The `forecast_widget` displays an available status in case the demand of the move is expected to be fulfilled and there is no `forecastExpectedDate`: https://github.com/odoo/odoo/blob/a46cdcd9d0b575eb668ed738565637f346bbdf7b/addons/stock/static/src/widgets/forecast_widget.xml#L1-L19 https://github.com/odoo/odoo/blob/4fbd88ad3ac2d92b47b024b96f1c40ed4b3f97e3/addons/stock/static/src/widgets/forecast_widget.js#L15-L26 Now, the issue is that this `forecastExpectedDate` is currently unreliable in this use case as the `forecast_expected_date` of the SB component move is incorrectly computed to be False rather than matching its subcontracted receipt counter part. To be more precise, the `forecast_expected_date` is computed based on the report lines: https://github.com/odoo/odoo/blob/8b8b99e371fcf214b9c55fb2fbfca20f2ee66f53/addons/stock/models/stock_move.py#L579-L581 https://github.com/odoo/odoo/blob/8b8b99e371fcf214b9c55fb2fbfca20f2ee66f53/addons/stock/models/stock_move.py#L2701 The component move is an out move of SB from Stock to Production and is linked to the finished subcontracted move of SB from Production to Subcontracting. In particular, this finished subcontracted move (which is assigned) contributes to the 'reserved' out qties on the get go and leads to an already reserved out quantity of 1.0 even thought the move is purely external and linked to the subcontractor process: https://github.com/odoo/odoo/blob/ef89bc530ffae93a553003559ca9078b7a9d0653/addons/stock/report/stock_forecasted.py#L241-L268 In turn, the `demand_out` matched its `reserved_out` (even thought this reserved_out should be 0) so that no `in_transit` move is provided to provide an `expected_date`: https://github.com/odoo/odoo/blob/ef89bc530ffae93a553003559ca9078b7a9d0653/addons/stock/report/stock_forecasted.py#L426-L435 opw-6445209 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283177
When employees add leave for a day where the system had automatically recorded a missing attendance, the related negative extra hours are now reset correctly. This prevents incorrect overtime balances caused by system-generated midnight attendance records being missed.
Original PR description
Before this commit: --- When [`absence_management`](https://github.com/odoo/odoo/blob/b3444e4bd421a30229b0dc7c8d5eb6c78b8b51ed/addons/hr_attendance/models/res_company.py#L42) is enabled, a [scheduled…
Before this commit:
---
When [`absence_management`](https://github.com/odoo/odoo/blob/b3444e4bd421a30229b0dc7c8d5eb6c78b8b51ed/addons/hr_attendance/models/res_company.py#L42) is enabled, a [scheduled action](https://github.com/odoo/odoo/blob/b3444e4bd421a30229b0dc7c8d5eb6c78b8b51ed/addons/hr_attendance/models/hr_attendance.py#L645) automatically creates an attendance record at [**12:00:00 AM**](https://github.com/odoo/odoo/blob/b3444e4bd421a30229b0dc7c8d5eb6c78b8b51ed/addons/hr_attendance/models/hr_attendance.py#L649) to mark negative extra hours for employees with missing attendance.
<img width="1147" height="474" alt="image" src="https://github.com/user-attachments/assets/833a4387-bc20-4bb7-817d-9ebe9afa7d71" />
If an employee later creates a leave covering this autogenerated attendance, the extra hours should be reset to `0`. However, this does not happen.
#### Video demonstration:
https://drive.google.com/file/d/1DTNQuQ3uV5nOUVMBazCDo0hBZbKJZUIW/view
This happens because the [domain](https://github.com/odoo/odoo/blob/b3444e4bd421a30229b0dc7c8d5eb6c78b8b51ed/addons/hr_holidays_attendance/models/resource_calendar_leaves.py#L8) used to fetch attendances for [`_update_overtime`](https://github.com/odoo/odoo/blob/b3444e4bd421a30229b0dc7c8d5eb6c78b8b51ed/addons/hr_holidays_attendance/models/resource_calendar_leaves.py#L34) compares the attendance `check_in` and `check_out` datetimes with the leave `date_from` and `date_to` datetimes.
The leave datetimes are aligned with the employee's working schedule. For example, if the working hours are **8:00 AM–5:00 PM**, the leave is stored from `{date, 8:00 AM}` to `{date, 5:00 PM}`. In contrast, the scheduled action creates the autogenerated absence attendance at **12:00:00 AM** (in the user's timezone). Since this attendance falls outside the leave datetime range, it is excluded from the domain, and `_update_overtime` is never called for it.
After this fix:
---
Instead of building the domain using the leave datetime range, the domain is built using the leave date range. This ensures that all attendances for the affected dates, including autogenerated absence attendances created at midnight, are included and their extra hours are updated correctly.
OPW: 6385811
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#281123This fixes a setup problem that could occur when Australian localization was installed without the related Australian reports module. The change keeps specialized report logic with the module that provides it, preventing failures in uncommon installation combinations.
Original PR description
We had a case where l10n_au and account_reports were installed together, but not l10n_au_reports (manually uninstalled ?). Since the custom engine was used on expressions in l10n_au, this failed. Custom engines should always be used and declared within the same module (or a submodule of the one defining the handler) to avoid such issues. opw-6451274 Forward-Port-Of: odoo/odoo#282790
This fix stops Accounting payment terms from crashing when a user enters a zero or negative day value for an end-of-month due date. Users now receive the intended validation message when saving, improving reliability and preventing confusing error screens.
Original PR description
Steps to reproduce: - Install `Accounting` module - Payment Terms > Create NEW - Add a new Due Term line with "Days end of month on the" and a negative amount of days(eg: -1) Traceback: `ValueError: day is out of range for month` When `days_next_month` is set to a negative value, it is passed directly to `relativedelta` as the 'day' value. Since a negative value is not a valid day of the month, the due-date computation raises a `ValueError`. Use the end of the month for the calculation when `days_next_month` is non-positive. This prevents the traceback while computing the payment term and allows the proper validation error to be raised when the record is saved. opw-6453640 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283865 Forward-Port-Of: odoo/odoo#281904
Sales orders that require a customer signature are now checked correctly during payment, helping prevent orders from being paid before required approval is captured. This reduces the risk of incomplete sales validation in Sales and related point-of-sale flows.
Original PR description
See also: - https://github.com/odoo/enterprise/pull/127041 Forward-Port-Of: odoo/odoo#283579 Forward-Port-Of: odoo/odoo#280403
Cloud storage download links can now be created with a longer expiry time when a business process needs an external service to fetch the file later. Existing behavior stays the same by default, reducing disruption while preventing failed delayed downloads for affected flows.
Original PR description
Some features hand a cloud storage download URL to an external service that may fetch it later. The default five-minute lifetime is too short for those flows. ### Steps to reproduce 1. Configure a cloud storage provider (e.g. cloud_storage_google). 2. Upload a large file from the web client, so it is stored in the cloud. 3. Generate a download URL for a consumer that may fetch it after five minutes. 4. The URL expires before the consumer fetches it. ### Cause The Google and Azure providers always use the default download URL lifetime, so callers cannot request a longer-lived URL. ### Fix Read an optional cloud_storage_download_url_time_to_expiry context value when generating a download URL. Keep the existing five-minute lifetime as the default for all current callers. opw-5424132 Related Enterprise PR: odoo/enterprise#105967 Forward-Port-Of: odoo/odoo#246443
Fixes an accounting issue where reversing and recreating a foreign-currency invoice could miss exchange difference and cash basis tax entries. Businesses using multi-currency cash basis accounting now get accurate automatic postings without manually resetting and reposting the credit note.
Original PR description
### Issue before this commit: When using the "Reverse and Create Invoice" feature on a posted invoice with a foreign currency and Cash Basis enabled, the expected Exchange Difference and Cash Basis…
### Issue before this commit: When using the "Reverse and Create Invoice" feature on a posted invoice with a foreign currency and Cash Basis enabled, the expected Exchange Difference and Cash Basis tax entries are not generated upon the automatic reconciliation. The credit note is successfully created and reconciled with the original invoice, but the P&L exchange difference and the cash basis transition lines are completely missing. Currently, the only workaround is to manually reset the generated credit note to draft and re-post it, which forces the system to correctly calculate the currency rate differences and generate the missing entries. ### Steps to reproduce the issue: 1. Download Accounting 2. Go to Settings > Cash basis. Tick it and set as 'Base Tax Received Account' an account like 201000 Current Liabilities 3. Go to Chart of Accounts > search your account (ex. 201000 Current Liabilities) and be sure the flag of 'Allow Reconciliation' is on 4. Go to Taxes > 15% sales > set 'Tax Exigibility' as Based on Payment and 'Cash Basis Transition Account' always as 201000 Current Liabilities 5. Go to Currencies and set a new currency like MXN inserting tax rates as: 1. 1 july 2026: 20$ 2. 15 july 2026: 15$ 6. Create a new invoice with price 100 and 15% tax, set MXN as currency for the journal, set the date as 1 july and confirm it 7. Click on 'Credit Note', then 'Reverse and Create Invoice' and confirm it 8. go back to the invoice and see that after the total amount there is a new line 'Reversed on...' 9. After that line there should also be the line with the Exchange Difference since the tax rates for MXN currency were different at the moment of the invoice and at the moment of the credit note. This is only created by resetting to draft the credit note and confirm it again. ### Cause of the issue: In the account.move.reversal wizard, when is_modify = True (Reverse and Create), the system triggers _reverse_moves with cancel=True. At the end of the _reverse_moves method, the newly created reverse moves are automatically posted and reconciled. However, this automatic posting is executed with move_reverse_cancel=True injected into the context: reverse_moves.with_context(move_reverse_cancel=cancel)._post(soft=False). When the reconciliation engine (_reconcile_plan_with_sync and _create_exchange_difference_moves) detects this specific context key, it intentionally bypasses the creation of both the exchange difference P&L moves and the cash basis entries, treating the reversal as a pure administrative cancellation rather than a financial operation with currency fluctuations. ### Reason to introduce the fix: To ensure financial accuracy and compliance, especially when cash basis and multi-currency are involved, a reversal on a different date must reflect the actual exchange rate fluctuations and properly trigger cash basis rules. By removing the move_reverse_cancel context injection during the automatic posting of the reverse moves, we allow the native reconciliation engine to evaluate the newly computed balance (based on the credit note's date) against the original invoice. This ensures that exchange differences and cash basis journal entries are automatically and accurately generated on the first attempt. opw-6399867 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283306 Forward-Port-Of: odoo/odoo#281498
Product videos in the online shop carousel now load only when their slide is shown, so preview images appear crisp instead of blurry. This improves the product page experience for shoppers viewing video media.
Original PR description
Steps to reproduce: =================== 1. Add a video (e.g. a YouTube URL) to a product from the Sales app. 2. Open the product page on the website. 3. Slide the carousel to the video. => The video…
Steps to reproduce: =================== 1. Add a video (e.g. a YouTube URL) to a product from the Sales app. 2. Open the product page on the website. 3. Slide the carousel to the video. => The video preview cover is blurry. Root cause: =========== The product images are rendered in a carousel (the shop_product_carousel template in ) where only the first slide gets the "active" class; https://github.com/odoo/odoo/blob/af1b3ee2e7ac56a35bff5e030c3a831c27dbcf24/addons/website_sale/views/templates.xml#L3224-L3226 every other slide is "display: none". A product video is rendered as a live <iframe> inside its slide, so when the video is not the first media its iframe loads while its container has no dimensions (0x0). The embedded player then initializes as a small mobile player and loads a low resolution cover thumbnail (120x90), which looks blurry once the slide is shown at full size. Reloading only the iframe while the slide is visible fixes it, a full page reload does not. Fix: ==== Defer loading the video iframes located on hidden slides their src is moved to a data-src attribute on start and restored once the slide becomes visible. The player then initializes at full size and loads a high resolution cover. opw-6349394 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#282508 Forward-Port-Of: odoo/odoo#274002
This fix ensures restaurant self-order payments save order details before sending the customer to the online payment page. It prevents customer information and pickup times from disappearing when a customer returns from payment, improving reliability for takeout orders.
Original PR description
**Setup** * Increase the debounce time of `debouncedSynchronizeLocalDataInIndexedDB` to **5 seconds** to reproduce the issue deterministically. * Configure a restaurant with **Self Ordering** enabled…
**Setup** * Increase the debounce time of `debouncedSynchronizeLocalDataInIndexedDB` to **5 seconds** to reproduce the issue deterministically. * Configure a restaurant with **Self Ordering** enabled (`QR Menu + Ordering`). * Configure **Mollie** as the **only** online payment method. **Reproduction** 1. Place a **takeout** order through the mobile menu. 2. Select a pickup time, enter the required customer information (including a mobile number), and proceed to the payment page. 3. Verify from the backend that the draft order contains the expected data (customer/partner and `preset_time`). 4. Press the browser **Back** button to return from the payment page. 5. Check the draft order in the backend again. [video](https://drive.google.com/file/d/1kNWpYuo79mYMV3eMelwJ5IDFeWUc7zsD/view) **Observed result** * The draft order loses its previously synced information. In particular, the **partner/customer** data (and other synced fields such as `preset_time`) are removed. **Expected result** * Returning from the payment page should not modify the draft order. All previously synced data should remain intact. **Cause** - When there's only a single payment method, it's [auto-selected](https://github.com/odoo/odoo/blob/161715c850496d3683baa5d1600380470d0b5ff5/addons/pos_self_order/static/src/app/pages/payment_page/payment_page.js#L21-L22) and `checkAndOpenPaymentPage` immediately opens the payment page via[ window.open()](https://github.com/odoo/odoo/blob/161715c850496d3683baa5d1600380470d0b5ff5/addons/pos_online_payment_self_order/static/src/app/pages/payment_page/payment_page.js#L35). - The order's local data is saved to IndexedDB on a 300ms debounce. If the redirect fires before that debounce completes, the save is cancelled, leaving IndexedDB out of sync with the in-memory order **Fix** - Before opening the payment URL, explicitly flush the order to IndexedDB using the `synchronizeLocalDataInIndexedDB`, ensuring the local data is persisted before the page navigates away. opw-6231478 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283800 Forward-Port-Of: odoo/odoo#272724
Restaurant point-of-sale bill splitting now handles combo meals with the same choice selected multiple times. This ensures staff can split bills accurately, avoiding under-selected combo items and reducing payment mistakes.
Original PR description
Steps to reproduce: --- - Install `pos_restaurant` demo data. - Open a session for `Restaurant`. - Go to any table. - Add a Sushi Lunch Combo line with the same sushi choice multiple times. - Click the "More" button and select "Split". - Click on any combo product line. Issue: --- - Only one quantity is selected instead of the full combo choice quantity. Cause: --- - Combo child lines were incremented by a fixed value of `1` during split, without considering the quantity ratio between the combo root line and combo child lines. Fix: --- - Compute the selection step based on the combo line quantity relative to the combo root line quantity. - Properly update split quantities for repeated combo choices. - Added test coverage for combo lines with repeated quantities. task-6197879 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283876 Forward-Port-Of: odoo/odoo#264049
Website editors can now directly edit previously locked sections of mega menu templates, such as footers and logo areas. This makes menu customization smoother and reduces the need for workarounds when building website navigation.
Original PR description
### Issue: Some elements in mega menu templates are not editable inline in the website builder. ### Steps to reproduce: - Go to Website > Site > Menu Editor and add a mega menu item. - Edit the mega menu and set its template (e.g. 'Thumbnails' or 'Logos'). - Try to inline edit certain sections (e.g. footer or logos container). ### Reason: `BuilderContentEditablePlugin` does not apply `contenteditable="true"` to these elements because they do not match any of the selectors defined in `content_editable_selectors`. ### Fix: Add missing element classes to `content_editable_selectors` so that these elements become editable inline. task-[6116253](https://www.odoo.com/odoo/project/974/tasks/6116253) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283975 Forward-Port-Of: odoo/odoo#263021
Portal pages now show the expected breadcrumb navigation next to page titles across several Odoo apps. This helps customers and portal users understand where they are and navigate back more easily when viewing orders, projects, timesheets, and related records.
Original PR description
*=account, hr_timesheet, loyalty, mrp_subcontracting, project, purchase, sale, website_crm_partner_assign Steps to reproduce: 1. install sale 2. Create and confirm a sale order for a portal user 3.…
*=account, hr_timesheet, loyalty, mrp_subcontracting, project, purchase, sale, website_crm_partner_assign Steps to reproduce: 1. install sale 2. Create and confirm a sale order for a portal user 3. Login as a portal user 4. Open sale orders Issue: - Breadcrumbs are not visible beside the title. Cause: - After this commit https://github.com/odoo/odoo/commit/bba2fc505f5d0b4770eacc6877155b1aeda6d772 Variables are passed as attributes directly on the element, but breadcrumbs_searchbar was passed to portal_layout, but the nested portal_searchbar no longer received it. As a result, portal list pages rendered their title instead of the breadcrumb home link. Solution: - Pass breadcrumbs_searchbar directly to portal_searchbar Alternative: - An alternative would be to propagate t-call parameters to slot content in QWeb or changes the condition for breadcrumbs visibility related enterprise pr: https://github.com/odoo/enterprise/pull/118352 opw-6232899 Forward-Port-Of: odoo/odoo#266020
The Attendance location warning dialog now closes properly when employees choose Discard. This prevents users from getting stuck on the check-in or check-out confirmation popup when browser location access is blocked.
Original PR description
Steps to reproduce: -------------------------------------------- 1. Install Attendance module. 2. Enable `Device & Location Tracking` & `Attendance from Backend` in settings. 3. Block location access…
Steps to reproduce: -------------------------------------------- 1. Install Attendance module. 2. Enable `Device & Location Tracking` & `Attendance from Backend` in settings. 3. Block location access from the browser for this site (Site settings) 4. Try to checkIn/checkOut from the Dot in the systray 5. We'll have one confirmation pop-up asking to Proceed Anyway OR Discard Observation: -------------------------------------------- On clicking the discard button, Nothing happens. Issue: -------------------------------------------- In `confirmChecking()`, the `cancel` callback was defined as an arrow function using an expression body. In JavaScript, an assignment expression returns the assigned value. Since `this._attendanceInProgress` is set to `false`, the callback implicitly returns `false`. `ConfirmationDialog.execButton()` treats a `false` return value as a signal to keep the dialog open (used intentionally to block closing on validation failure) This caused the dialog to never call `this.props.close()`, leaving it permanently open when Discard was clicked. https://github.com/odoo/odoo/blob/5e84fdd99e34836a15cadc4fdf4b6bc449727e58/addons/web/static/src/core/confirmation_dialog/confirmation_dialog.js#L75-L89 Solution: -------------------------------------------- Change the `cancel` callback from an expression body to a block body, A block body arrow function returns `undefined` by default. This ensures `execButton` does not interpret the return value as a 'keep dialog open' signal, and correctly calls `this.props.close()` to dismiss the dialog. opw-6462439 Forward-Port-Of: odoo/odoo#281702
Sales users limited to their own documents can now cancel orders that include loyalty program points without hitting an access error. This prevents blocked cancellations while still cleaning up temporary loyalty point records correctly.
Original PR description
Steps to produce: --- - Install `sale_management` and `sale_loyalty` module without demo. - From sales > products > discounts & loyalty, create new loyalty card program and save. - Now create new…
Steps to produce: --- - Install `sale_management` and `sale_loyalty` module without demo. - From sales > products > discounts & loyalty, create new loyalty card program and save. - Now create new product of 100$. - Create a user which have sales rights as `user: own documents only`. - With that user, create new sale order with product and confirm. - Try to cancel the order. Issue: --- - It shows the access error: ```py You are not allowed to delete 'Sale Order Coupon Points - Keeps track of how a sale order impacts a coupon' (sale.order.coupon.points) records. This operation is allowed for the following groups: - Sales/Administrator Contact your administrator to request access if necessary. ``` Root cause: --- - Users with the `Sales: Own Documents Only` access right only have read permissions ([1]). When they cancel a Sales Order, the `_action_cancel` method attempts to clean up the temporary pending points allocated to the order by calling `self.coupon_point_ids.unlink()`. Because this call is executed without elevated privileges, the system blocks the deletion and raises an Access Error Solution: --- - Added `.sudo()` to the `unlink()` call for `coupon_point_ids` in the `_action_cancel` method. This ensures the pending point records are cleaned up with the necessary elevated privileges. [1]https://github.com/odoo/odoo/blob/23af2b443735c6d3a2f64e44f9ea5da45638b052/addons/sale_loyalty/security/ir.model.access.csv#L16 opw-6453016 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284122 Forward-Port-Of: odoo/odoo#281477
This fix stops online shop orders from being confirmed when a portal customer reaches payment validation with an empty cart. It helps avoid invalid sales orders and keeps order records accurate after customers remove all items before checkout.
Original PR description
Calling `/shop/payment/validate` as a portal user with an empty cart confirms the empty sale order. Steps to reproduce: - Sign in as a portal user. - Add a product to the cart. - Remove the product. - Go to `/shop/payment/validate`. - The empty sale order is confirmed. opw-6430637 Forward-Port-Of: odoo/odoo#283786 Forward-Port-Of: odoo/odoo#280924
The Sign module now keeps existing rules that hide the "Mark Done" button in the activity scheduling wizard while adding its own condition. This prevents the button from appearing at the wrong time and avoids conflicts with other modules such as Calendar.
Original PR description
Previously, the sign module was completely overwriting the `invisible` attribute on the "Mark Done" (`action_schedule_activities_done`) button in the activity schedule wizard. This inadvertently discarded base conditions (such as hiding the button when `has_error` is true) and caused conflicts with other modules (like `calendar`) that also need to modify this button's visibility. This commit updates the view inheritance to safely append the sign condition using `add` and `separator="or"`, preserving all existing visibility rules. Task-6499751
This update keeps PDF document navigation working with newer and older versions of the PDF library used by Accountant Knowledge. It helps prevent errors when processing PDF outlines, links, and bookmarks after library updates.
Original PR description
On latest versions of PyPDF, the `outlines` attribute was renamed to `outline`, we now handle both attributes to provide compatibility with both versions. A similar issue arises with the `addLink` method, which was renamed to `add_link`, and later replaced by `add_annotation`. Another similar issue arises with the `add_bookmark` method, which was replaced by `add_outline_item`. task-6474715 version-19.4
Fixed an issue in Odoo Sign where declining a signature request with a reason could trigger an error instead of completing smoothly. The decline dialog now closes before the confirmation message appears, preventing duplicate processing and improving the signing experience.
Original PR description
Version: 19.4 Steps to reproduce: - Create a sign request with a signature and send it to a user - Decline the document as administrator with a reason Issue: Opening the thank you dialog before closing the decline dialog caused both actions to be processed together. This made the thank you dialog get built twice and both attempts were already destroyed before orm.call, raising a traceback. Fix: Close the decline signature dialog first, then open the thank you dialog. Task id - 6471923
This fix lets users enter and compare budgets on the Moroccan Profit and Loss report, which previously failed because the report used multiple columns. Budget comparisons now consistently use the correct balance figures, so budget amounts no longer disappear.
Original PR description
Before this commit, it was impossible to use budget on the Moroccan P&L, for the following reasons: - The feature was designed for one-column reports. MA's P&L uses 3, one of which is the total of…
Before this commit, it was impossible to use budget on the Moroccan P&L, for the following reasons:
- The feature was designed for one-column reports. MA's P&L uses 3, one of which is the total of the two others.
=> We remove that requirement, and make sure to always select the 'balance' column as the reference for the budget comparison.
- When trying to input a budget amount in the report, the amount disappeared entirely.
=> This was because the total column of report was not using 'balance' as its expression label. We fix that by rewriting the expression labels of that report.
The fact we hardcode the use of 'balance' is arguable. It is however not possible here to rely on some custom handler to change a specific option key that would be used to generate the budget comparison data, since some of those data need to be generated in the get_options, before _custom_options_initializer even gets called. This is the simplest approach, and this case is rare enough for us to deem it acceptable.
opw-6385229
Forward-Port-Of: odoo/enterprise#129003
Forward-Port-Of: odoo/enterprise#128266Odoo now saves successful UrbanPiper delivery provider confirmations as soon as they reach the server. This prevents providers from showing the wrong enabled or disabled status in POS when no cashier screen was available to receive the update.
Original PR description
When a POS session opens, every configured delivery provider is enabled through UrbanPiper. UrbanPiper later confirms the operation through a store_action webhook. Previously, Odoo only forwarded this confirmation to the POS frontend. The frontend was then responsible for persisting the new provider state. If no POS client received the notification, the confirmed state was not saved. Consequently, a provider could be enabled in UrbanPiper while appearing disabled in the POS. Persist successful store_action callbacks directly when they are received by the server. Update only the affected provider and let the frontend consume the resulting state without writing its potentially stale provider-state mapping back to the server. opw-6455361 Forward-Port-Of: odoo/enterprise#127789
This fixes an issue where social media users could receive an access error when liking a stream post. Likes are now processed through the appropriate backend flow, so engagement actions work reliably without disrupting users.
Original PR description
Bug === When a social user like a stream post, an access error is raised because he has no write access on it. Task-6425391 Forward-Port-Of: odoo/enterprise#128937 Forward-Port-Of: odoo/enterprise#125973
This update corrects how taxable amounts are calculated in Peruvian electronic invoices, especially for down payments and taxes that affect later tax bases. It helps prevent invoice rejection by Peru’s electronic invoicing service due to small rounding mismatches.
Original PR description
**Steps to reproduce:** - Install Accounting, Sales and l10n_pe_edi - Switch to a Peruvian company (e.g. PE Company) - Create a SO: * Customer: [a Peruvian customer] * Order Lines: | Product |…
**Steps to reproduce:**
- Install Accounting, Sales and l10n_pe_edi
- Switch to a Peruvian company (e.g. PE Company)
- Create a SO:
* Customer: [a Peruvian customer]
* Order Lines:
| Product | Quantity | Unit Price | Taxes |
| ------- | -------- | ---------- | ------- |
| any | 3.00 | 123.50 | VAT 18% |
| any | 2.00 | 27.544216 | 0% Ina |
| any | 1.00 | 43.490867 | 0% Exo |
- Confirm the SO
- Create a 40% down payment
- Confirm the down payment
- Process it to sent it to Peru UBL 2.1
**Issue:**
The following error message is returned by the OSE:
`3272|La base imponible a nivel de línea difiere de lainformación consignada en el comprobante - Detalle: xxx.xxx.xxx ticket : 20260000000000221633458 error: Error en la Linea Nro. :1. : 3272 (nodo: "cac:TaxSubtotal/cbc:TaxableAmount" valor: "148.20")`
**Cause:**
In the XML, one line has 148.19 for "cbc:LineExtensionAmount", but 148.20 for "cac:TaxSubtotal/cbc:TaxableAmount".
The issue is coming from the fact that "base_amount_currency" is used instead of "total_excluded_currency" for the computation of "cac:TaxSubtotal/cbc:TaxableAmount".
**Issue 2:**
When a tax is impacting the base amount of a following tax, its tax amount is not taken into account in "total_excluded_currency".
opw-6235909
Forward-Port-Of: odoo/enterprise#128881
Forward-Port-Of: odoo/enterprise#122310Users can now open and apply an opening date in Tax Returns without encountering an error. The change updates how the page references screen elements so it remains compatible with the latest interface framework.
Original PR description
Currently, an error occurs when user opens tax returns. Steps to replicate: - Install `accountant`. - Open Accounting > Accounting > Tax Returns. - Add an `Opening date` and click apply. Error: ```…
Currently, an error occurs when user opens tax returns.
Steps to replicate:
- Install `accountant`.
- Open Accounting > Accounting > Tax Returns.
- Add an `Opening date` and click apply.
Error:
```
Uncaught Promise > Ref is undefined or null
OwlError: Ref is undefined or null
Error: Ref is undefined or null
at createRef (http://localhost:8069/web/assets/1f0e4b3/web.assets_web.min.js:1099:47)
at AccountReturnKanbanRenderer.template_account_reports_account_return_kanban_renderer (eval at compile (http://localhost:8069/web/assets/1f0e4b3/web.assets_web.min.js:1503:228), <anonymous>:13:16)
```
Cause:
- Error occurs after a recent [PR].
- In OWL 3, the `t-ref` directive expects a `signal`, whereas here it is provided with a string `root`, causing the error.
- OWL 2 allowed `t-ref` to be used with a string, so a new `t-custom-ref` directive was introduced to retain support for string-based references to DOM elements.
Solution:
- Replaced `t-ref` to `t-custom-ref`.
- Please refer to [1] and [2].
[PR]: https://github.com/odoo/enterprise/pull/128391
[1]: https://github.com/odoo/odoo/blob/a460aabc659af8ff6282dac77dbaf71fd3ff30f5/addons/web/static/src/owl2/owl3_compatibility_layer.js#L14
[2]: https://github.com/odoo/odoo/pull/246876
No Task IDThis fixes an issue in Odoo Studio approval workflows so approval responsibilities can be delegated as intended. It helps businesses keep approval processes moving when the original approver is unavailable.
Original PR description
opw-6321766 Forward-Port-Of: odoo/enterprise#128666 Forward-Port-Of: odoo/enterprise#122441
This fix prevents Odoo Studio from crashing when users edit fields that are added dynamically in accounting-related screens. Instead of showing an error, Studio now handles these cases gracefully and hides internal helper fields that should not be edited.
Original PR description
* = account_invoice_extract, l10n_nl_reports Example of steps: - Install web_studio and `accountant` - Open the corresponding form view in Studio - With debug mode toggle "Show invisible Elements"…
* = account_invoice_extract, l10n_nl_reports Example of steps: - Install web_studio and `accountant` - Open the corresponding form view in Studio - With debug mode toggle "Show invisible Elements" and edit "Invisible" on the second partner_id field - Traceback `normalize()` compares the combined arch without the studio customization to the one with it, in order to compute the smallest possible set of xpaths. To do so, it calls `apply_inheritance_specs` (the low-level function from `odoo.tools.template_inheritance`) directly on the statically combined arch. Some models add or duplicate nodes dynamically in `_get_view()` (Python postprocessing, run after the static view combination). A studio operation can target such a node, since it is what the user actually sees and clicks on. But that node has no counterpart in the purely static combined arch used by `normalize()`, so `apply_inheritance_specs` raises a ValueError. `edit_view()` only catches `ValidationError` to fall back to an un-optimized (but valid) studio arch instead of failing the request. Since the low-level function raises a plain `ValueError` here, that fallback never triggers, and the exception is not caught anywhere. To fix this, we will keep the behavior from version 18.0 and catch the ValueError raised by `apply_inheritance_specs` in `normalize_with_keyed_tree` and re-raise it as a ValidationError, like `ir.ui.view.apply_inheritance_specs` already does elsewhere. This lets `edit_view()`'s existing fallback handle the case gracefully instead of crashing. Additionally, the two models responsible for the dynamically-added nodes described above are fixed at the source. `account_invoice_extract`'s duplicated `partner_id` field and `l10n_nl_reports`'s injected `company_id` field are now marked with `data-used-by`, the same attribute `_add_missing_fields` already sets in `ir_ui_view.py` for the fields it adds. Studio already skip rendering and computing xpaths for any node carrying this attribute (since https://github.com/odoo/enterprise/pull/92862), so these nodes are no longer exposed to the user and can no longer produce a studio operation that `normalize()` is unable to locate. opw-6332911 Forward-Port-Of: odoo/enterprise#127009 Forward-Port-Of: odoo/enterprise#122829
This fix keeps Australian report calculation rules together with the reporting component that supports them. It prevents errors when Australian localization and accounting reports are installed without the dedicated Australian reports module, improving stability for affected setups.
Original PR description
We had a case where l10n_au and account_reports were installed together, but not l10n_au_reports (manually uninstalled ?). Since the custom engine was used on expressions in l10n_au, this failed. Custom engines should always be used and declared within the same module (or a submodule of the one defining the handler) to avoid such issues. opw-6451274 Forward-Port-Of: odoo/enterprise#128132
Aged Receivables and Aged Payables reports now calculate aging periods correctly when horizontal groups are applied. This prevents incorrect amounts from appearing in older period columns, helping finance teams rely on grouped aging reports for accurate follow-up and reporting.
Original PR description
Problem: When using horizontal groups in Aged Receivables / Aged Payables reports, the amounts shown in the Older periods are incorrect. Steps to reproduce: 1. Activate debug mode 2. Go to Accounting…
Problem: When using horizontal groups in Aged Receivables / Aged Payables reports, the amounts shown in the Older periods are incorrect. Steps to reproduce: 1. Activate debug mode 2. Go to Accounting > Configuration > Horizontal Groups 3. Add a new horizontal group that results in at least 2 groups 4. Go to Accounting > Reporting > Aged Receivables / Aged Payables 5. Apply the horizontal group created 6. Notice how the amount in the Older period is incorrect, different from before applying the horizontal group. (It may be coincidentally correct, you can check by applying different aging intervals until you find one that shows the issue) Cause: The periods were not correctly calculated. The number of periods was calculated based on the number of period columns, without taking into account the number of column groups. When using horizontal groups, period columns are duplicated for each group that exists after applying the horziontal group. This is not considered when calculating the number of periods, which results in calculating too many periods and therefore having incorrect durations for each period. opw-6374639 Forward-Port-Of: odoo/enterprise#127570
This fix prevents a rare crash in the Hungarian Intrastat reporting module when company data is checked in unusual access-right situations. It is mainly a safeguard for future changes or customizations, as the issue is not expected through the standard user interface.
Original PR description
Due to some trouble with tests, we found that in some cases, this function is called on the root company, and if the user does not have the access rights to read data from the company (users with system rights have them by default), it will cause a crash. This situation is not possible with the standard UI, but we fix it in case it becomes possible in a future version or customization. Forward-Port-Of: odoo/enterprise#128218
WhatsApp messages now send cloud-stored attachments as accessible links instead of empty files. This ensures recipients receive the actual document while keeping existing behavior for locally stored attachments.
Original PR description
WhatsApp attachments were delivered as empty (0 byte) files when they were stored through the cloud_storage module. ### Steps to reproduce 1. Install and set up whatsapp and a cloud storage module (e.g. cloud_storage_google). 2. Send a file through WhatsApp. 3. The recipient receives an empty file. ### Cause A cloud stored attachment keeps only a reference to its remote data, so its raw field holds no bytes. The integration uploaded those empty bytes to WhatsApp. ### Fix Use the attachment HTTP stream to generate a long-lived cloud storage URL and pass it to WhatsApp as the media link. Pass ordinary remote attachment URLs directly, and keep uploading local attachment bytes as before. opw-5424132 Related Community PR: odoo/odoo#246443 Forward-Port-Of: odoo/enterprise#105967
This update prevents a rare crash when Belgian Intrastat reporting is accessed in unusual company permission scenarios. It makes the process more reliable for future customizations or edge cases, without changing normal user workflows.
Original PR description
Due to some trouble with tests, we found that in some cases, this function is called on the root company, and if the user does not have the access rights to read data from the company (users with system rights have them by default), it will cause a crash. This situation is not possible with the standard UI, but we fix it in case it becomes possible in a future version or customization. Forward-Port-Of: odoo/enterprise#128212
Financial reports now keep the correct yearly date range when users switch between companies with different fiscal year settings. This prevents reports from carrying over dates from the previously selected company, improving confidence in multi-company reporting.
Original PR description
Fix year-mode date filter when switching between companies with different fiscal years With two companies configured: one using a standard fiscal year and one using an offset fiscal year, switching between them could produce incorrect date ranges. This happened because the previous company’s `date_to` value was reused to compute the current period for the newly selected company, and vice versa. The fix is to use the `date_to` year instead and select the latest fiscal year ending in that same year. Forward-Port-Of: odoo/enterprise#117603
Tax returns can now be submitted without being blocked by incomplete settings on tax groups that have no related transactions. This prevents unnecessary interruptions during tax closing while still checking the configuration that is actually used.
Original PR description
…ax closing Steps to reproduce: - Remove the tax payable and receivable accounts of a tax group for which no move exists. - Open the tax returns view, set the opening date and submit the tax return -> Odoo prevents going further because the tax group configuration isn't fully done, but it's useless to ensure that for tax groups that aren't used. Forward-Port-Of: odoo/enterprise#128197
The AI website livechat snippet now has a preview image again in the website builder. This prevents the uninstalled livechat option from appearing broken, making the page-building experience clearer for users.
Original PR description
Problem: 1) The preview image of the livechat snippet was removed in this [commit][1] and wasn't replaced with another image. As a result, the uninstalled livechat snippet doesn't display properly in the website builder. Solutions: 1) An image has been added `ai_livechat.png` which is shown on preview Note: This fix will change in master to be up to date with current website snippet previews. The location will be moved to `snippet_previews` and the file type will be changed to `.webp` [1]: https://github.com/odoo/enterprise/commit/df05441e469157890253b5550b5f8735723b28fb Task-5248712 Forward-Port-Of: odoo/enterprise#126361
This change updates internal subscription tests so they stay aligned with recent related platform changes. It helps maintain release quality by ensuring subscription flows continue to be validated correctly, with no expected change for end users.
Original PR description
See also: - https://github.com/odoo/odoo/pull/280403 Forward-Port-Of: odoo/enterprise#128610 Forward-Port-Of: odoo/enterprise#127041
Fixed an issue where the online shop could show an error if a published rental product had all of its variants deleted. This keeps the storefront accessible for shoppers while still preventing incomplete products from being added to the cart.
Original PR description
Currently, an error occurs when user deletes all the variants of a product and opens the website raises an error. Steps to replicate: - Install `website_sale_renting`, open settings and turn on…
Currently, an error occurs when user deletes all the variants of a product and opens the website raises an error. Steps to replicate: - Install `website_sale_renting`, open settings and turn on `Product Variants`. - Create a new product `test` , give an attribute and 2 values. - Click on the `Variants` smart button, select all and delete. - Publish this produce in website and open shop on website. Error: ``` ValueError: Expected singleton: product.product() ``` Cause: - Issue occurs after a recent change (check [PR]) that added a check if product is donation. - As the user deleted all the variants of the product `test`, when flow reaches here [1] the `self.product_variant_id` is an empty recordset and then the method `_can_be_added_to_current_cart()` calls `_is_donation()` [2] which raises a singleton error [3]. Solution: - If the product doesnt have any variants (based on previous versions) we return true, while the product will still not be able to be added to the cart by [this] `UserError`. [PR]: https://github.com/odoo/enterprise/pull/118130 [1]: https://github.com/odoo/enterprise/blob/639d303aefb51ae7d426ff1d83f2aa7e652187e3/website_sale_renting/models/product_template.py#L129 [2]: https://github.com/odoo/enterprise/blob/639d303aefb51ae7d426ff1d83f2aa7e652187e3/website_sale_renting/models/product_product.py#L21 [3]: https://github.com/odoo/odoo/blob/5dc090a2f449dc05284a760cbdd11a94b51e5457/addons/website_sale/models/product_product.py#L306 [this]: https://github.com/odoo/odoo/blob/5dc090a2f449dc05284a760cbdd11a94b51e5457/addons/website_sale/controllers/cart.py#L127-L131 sentry-7635385579
Portal users can now see the expected breadcrumb navigation next to page titles across several customer-facing areas. This makes it easier for customers to understand where they are and navigate back from portal list pages.
Original PR description
*=appointment, equity, helpdesk, planning_field_service, sale_subscription, sign Steps to reproduce: 1. install sale 2. Create and confirm a sale order for a portal user 3. Login as a portal user 4. Open sale orders Issue: - Breadcrumbs are not visible beside the title. Cause: - After this commit https://github.com/odoo/odoo/commit/bba2fc505f5d0b4770eacc6877155b1aeda6d772 Variables are passed as attributes directly on the element, but breadcrumbs_searchbar was passed to portal_layout, but the nested portal_searchbar no longer received it. As a result, portal list pages rendered their title instead of the breadcrumb home link. Solution: - Pass breadcrumbs_searchbar directly to portal_searchbar Alternative: - An alternative would be to propagate t-call parameters to slot content in QWeb or changes the condition for breadcrumbs visibility releted community pr: https://github.com/odoo/odoo/pull/266020 opw-6232899 Forward-Port-Of: odoo/enterprise#118352
This update makes an automated checkout certification test wait for the product screen before continuing. It reduces random test failures in build validation without changing the day-to-day user experience.
Original PR description
we face this error when running tour `FiskalyTour` with linked pr (which is completely independent of this module) and should not fail, but this can be considered as non-deterministic. waiting/confirming that product-screen is shown, before making the next move, solves the issue. build link: https://runbot.odoo.com/runbot/batch/2696526/build/121430872?debug=1 Forward-Port-Of: odoo/enterprise#128733 Forward-Port-Of: odoo/enterprise#127902
This fixes an issue where Brazilian point-of-sale tax adjustments could choose the wrong tax record when sales and purchase taxes shared the same setup details. The correction helps ensure tax adjustment entries stay balanced, reducing accounting errors for affected Brazilian POS transactions.
Original PR description
The chart template gives the same Avatax code and price_include_override to the sale and the purchase tax, and creates both in the same transaction. Without an explicit type_tax_use the lookup used to return either of them at random, and picking the purchase one left the entry unbalanced. The purchase taxes got their Avatax code in 18.4+. https://github.com/odoo/enterprise/pull/101072 runbot-945969 Forward-Port-Of: odoo/enterprise#128872 Forward-Port-Of: odoo/enterprise#128476