Thursday, February 26, 2026
25 changes · saas-18.4
Resolved issues and error corrections
Portal pages now correctly mark the page direction for right-to-left languages such as Arabic. This helps interface components like image galleries respond correctly to keyboard navigation, improving usability for RTL users.
Original PR description
Some libraries expect to find the language direction on the HTML element (e.g. Bootstrap). As we didn't set it, there were some issues. For instance on the website: - set the website language to some RTL language (e.g. Arabic) - drop an image gallery snippet and save - navigate with the keyboard to the carousel and start using the arrows to switch images => Pressing left should show the _next_ image, and pressing right should show the _previous_ image (contrary to LTR languages). This is illustrated by the image indicators at the bottom of the carousel (the 1st image is on the right, the last image on the left). But without `dir="rtl"` on the HTML element, the arrows keep their LTR behavior: pressing left goes to the previous image, and right to the next image. task-5109547 Forward-Port-Of: odoo/odoo#250257 Forward-Port-Of: odoo/odoo#240611
Sales orders grouped by status in Kanban now appear in the expected business workflow order instead of alphabetical order. This makes the Sales dashboard easier to read and helps users follow quotations and orders more naturally.
Original PR description
Steps to produce: --- - Install sales module. - Open sales module > orders > switch to kanban view. - Then make it group by status. Observation: --- - The order of status is not proper. - It comes as…
Steps to produce: --- - Install sales module. - Open sales module > orders > switch to kanban view. - Then make it group by status. Observation: --- - The order of status is not proper. - It comes as Cancelled, Quatation, Sale order, Quatation sent. Root cause: --- - When we perform Group By > Status, the method `web_read_group()` is executed. then in chain `_web_read_group()` calls `read_group()` without providing any explicit `orderby`. Inside `read_group()`, if orderby is not provided, it sets the order to the grouped field itself. - Inside `_read_group()`, the SQL query constructed with an order by clause on the grouped field (state). Therefore, the values are retrieved in alphabetical order as `cancel, draft, sale, sent`. Solution: --- - Define `group_expand` on the `state` field. During `read_group()`, `_read_group_fill_results()` calls this method and reorders the groups accordingly. - This overrides the alphabetical SQL order returned by `_read_group()` and ensures the correct logical status order in Kanban view. opw-5497664 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#248776
Point of Sale receipts now show the correct tax label when a fiscal position changes the tax applied to an order. This prevents customer receipts from displaying an outdated tax rate label even though the charged tax amount was already correct.
Original PR description
Steps: - Install l10n_be_pos_restaurant. - Create a restaurant POS configuration with presets. - Assign a fiscal position to one preset that replaces 21% tax with 6%. - Open a POS session and process an order using that preset. Issue: - The POS receipt still displays the 21% tax's tax group label, even though the 6% tax is correctly applied. Cause: - Fiscal position was not taken into account when computing the tax group label for POS receipt orderlines. Fix: - Apply the fiscal position when determining the POS receipt tax group label. Task-5899938 Forward-Port-Of: odoo/odoo#249697 Forward-Port-Of: odoo/odoo#248571
Users can now return to the Pay Runs view on mobile without the system crashing. The update adds a safeguard so the page only restores scrolling when the expected view area is available, improving navigation reliability.
Original PR description
**Steps to Reproduce:**
1. Open Payroll->Payslips->Pay Runs
2. Click on a Pay Run in Mobile View (Width < 600px).
3. Return to the previous view using the breadcrumb.
4. The system crashes with Traceback: TypeError: Cannot set properties of null (setting 'scrollLeft')
**Bug Cause:**
The base Kanban controller's scroll restoration logic assumes the presence of a '.o_renderer' element. In this specific hr_payroll view, The 'back' breadcumb returns to a view which does not have a (".o_renderer").
So, querySelector(".o_renderer") receives null, and crashes when accessing the 'scrollLeft' property.
**Solution:**
Added a safety check to verify the existence of the renderer element before attempting to manipulate its scroll position.
Task: 5971861
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prEarly payment discounts are now rounded consistently across the whole invoice instead of line by line. This prevents small accounting mismatches, such as one journal line showing a cent less than the expected discount, and keeps invoice totals and electronic exports aligned.
Original PR description
**PROBLEM** There is a rounding issue with early payment discount when cash discount tax reduction is set to always (upon invoice). The move.line created for the discount is computed by applying the discount to each line, rounding each line individually. But the early payment discount is computed by rounding globally. **STEP TO REPRODUCE** 1. Create a payment term, with early discount of 1%, and cash discount tax reduction set to 'Always (upon invoice)'. 2. Create an invoice with 4 identical lines, unit price 4.76€ and tax 15%. 3. set the payment term on the invoice and save. 4. Go to journal item, early payment discount is 0.20€. 5. toggle discount_amount column on the the journal item tab. 6. notice on the last line, that balance - discount_amount = 0.19€ instead of 0.20€ opw-5865308 Forward-Port-Of: odoo/odoo#247996
Opening notes entered when starting a point of sale session are now saved even if the store is not configured with a cash payment method. This helps businesses keep complete session records regardless of the payment methods they use.
Original PR description
Before this commit: -------------- - When the cash method was not available for config, opening notes values were not being stored in session data. After this commit: -------------- - Opening notes values will be stored in session data even when the cash method is not available for config. task-5474822 Forward-Port-Of: odoo/odoo#249953 Forward-Port-Of: odoo/odoo#243956
Fixed a small issue in delivery location selection where the page could try to focus an item even when no location was selected. This prevents confusing or unexpected behavior for users choosing delivery options.
Original PR description
Forward-Port-Of: odoo/odoo#250680
The Attendance list view now shows distinct labels for check-in and check-out location fields. This removes duplicate wording in the optional fields menu, making it easier for users to choose the correct attendance information to display.
Original PR description
Steps to reproduce: -------------------------------------- 1. Install the Attendance module 2. Go to the attendance list view 3. Click on the optional fields tray Observation: -------------------------------------- Duplicate field name Longitude (In) Issue: -------------------------------------- For the `in_location` field, a duplicate string was added in the list view Solution: -------------------------------------- Changed string to `Location (In)` for `in_location` field and changed string to `Location (Out)` for `out_location` field Before: <img width="348" height="511" alt="image" src="https://github.com/user-attachments/assets/109ff380-df4f-4dc6-ad01-a955d85436c7" /> After: <img width="330" height="503" alt="image" src="https://github.com/user-attachments/assets/894e6045-ec34-4296-8aff-f0e7bee32d9f" /> opw-5909500
This update improves internal website testing by providing more detail when a rare popup-related test fails. It helps developers diagnose intermittent issues faster, reducing time spent investigating test instability without changing customer-facing website behavior.
Original PR description
In order to fix the non-determinsitic test about popup that fails rarely, this commit gives more information in case of failure. Attempts to fix the tests in 0706aaef3894bbee6eea62679a2d89a3ee316f7b by adding timeout did not succeed.
Free-text product attributes with a single custom value are no longer shown twice on website product pages. This keeps product specifications cleaner and avoids confusing shoppers by displaying editable custom attributes only in their intended place.
Original PR description
### Issue: Due to this bug, an attribute with a single custom value will be shown in specifications and single value attributes. #### Steps to reproduce: 1- Create a product. Add a `Free text` attribute. 2- Navigate to product page on the website. 3- From website editor, style tab, switch `specification` style. 4- With specification style set to `None`, you can see this attribute in single value attributes list. 5- With other 2 styles you can see this attributes in specifications. Expected: In both steps 4 and 5, this attributes shouldn't be displayed there because it is already displayed in main attributes where you can set the value. Initially fix was to filter `ProductTemplateAttributeLine` in `_prepare_single_value_for_display`, however it would cause empty specification sections. To avoid that we also need to filter out single custom value attributes in `_prepare_categories_for_display`. opw-5484721 Forward-Port-Of: odoo/odoo#244234
This fix prevents an unexpected system error when Odoo checks certain view definitions that contain syntax problems. Instead of crashing due to a secondary internal error, the system can handle the original issue more reliably during testing or validation.
Original PR description
When syntax error will raise ``node`` will not assign. So, assign ``None`` before error will surpess. Note:- found it during testing. ``` Traceback (most recent call last): File…
When syntax error will raise ``node`` will not assign. So, assign ``None`` before error will surpess.
Note:- found it during testing.
```
Traceback (most recent call last):
File "/home/odoo/src/odoo/19.0/odoo/http.py", line 2273, in _serve_db
return service_model.retrying(serve_func, env=self.env)
File "/home/odoo/src/odoo/19.0/odoo/service/model.py", line 185, in retrying
result = func()
File "/home/odoo/src/odoo/19.0/odoo/http.py", line 2328, in _serve_ir_http
response = self.dispatcher.dispatch(rule.endpoint, args)
File "/home/odoo/src/odoo/19.0/odoo/http.py", line 2543, in dispatch
result = self.request.registry['ir.http']._dispatch(endpoint)
File "/home/odoo/src/odoo/19.0/odoo/addons/base/models/ir_http.py", line 355, in _dispatch
result = endpoint(**request.params)
File "/home/odoo/src/odoo/19.0/odoo/http.py", line 788, in route_wrapper
result = endpoint(self, *args, **params_ok)
File "/home/odoo/src/odoo/19.0/addons/web/controllers/dataset.py", line 32, in call_kw
return call_kw(request.env[model], method, args, kwargs)
File "/home/odoo/src/odoo/19.0/odoo/service/model.py", line 94, in call_kw
result = method(recs, *args, **kwargs)
File "/home/odoo/src/odoo/19.0/addons/web/models/models.py", line 113, in web_read
values_list: list[dict] = self.read(fields_to_read, load=None)
File "/home/odoo/src/odoo/19.0/odoo/orm/models.py", line 3490, in read
return self._read_format(fnames=fields, load=load)
File "/home/odoo/src/odoo/19.0/odoo/orm/models.py", line 3747, in _read_format
vals[name] = convert(record[name], record, use_display_name)
File "/home/odoo/src/odoo/19.0/odoo/orm/models.py", line 6686, in __getitem__
return self._fields[key].__get__(self)
File "/home/odoo/src/odoo/19.0/odoo/orm/fields.py", line 1746, in __get__
self.compute_value(recs)
File "/home/odoo/src/odoo/19.0/odoo/orm/fields.py", line 1917, in compute_value
records._compute_field_value(self)
File "/home/odoo/src/odoo/19.0/odoo/orm/models.py", line 4952, in _compute_field_value
determine(field.compute, self)
File "/home/odoo/src/odoo/19.0/odoo/orm/fields.py", line 81, in determine
return needle(*args)
File "/home/odoo/src/odoo/19.0/odoo/addons/base/models/ir_ui_view.py", line 366, in _compute_invalid_locators
if invalid_locator := assess_locator(source, spec):
File "/home/odoo/src/odoo/19.0/odoo/addons/base/models/ir_ui_view.py", line 330, in assess_locator
if node is None:
UnboundLocalError: local variable 'node' referenced before assignment
```
opw-5956964
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#250589This fix prevents certain asset loading failures from being reported after an automated tour has already ended. It reduces misleading test noise and helps teams focus on real issues in Odoo's core test infrastructure.
Original PR description
Similarly to commit https://github.com/odoo/odoo/commit/493bab4f460dd4069d5cb6805933b8088067ff17 hiding "failed to fetch" errors, this commit adds AssetsLoadingError as those represents "just" another category of failed assets request (i.e. lazy loaded) after tour termination. runbot-233826 Forward-Port-Of: odoo/odoo#248003
Fixed an issue in the HTML editor where adding columns from inside a list item could trigger an error. Users can now insert columns around list content more reliably, reducing interruptions while editing pages or documents.
Original PR description
Problem: When trying to add a column under a list item, a traceback occurs. Cause: The list item is removed during the operation, but the selection that is restored still references the removed list item. As a result, the selection is restored on a disconnected element, causing a traceback. Solution: Handle column insertion inside lists separately. In this case, according to the specifications, we split the list and insert the columns between the resulting lists (or after the list if the cursor is in the last list item). This avoids restoring the selection on a removed node. Steps to reproduce: - Add any list. - Run `/column` while the cursor is inside a list item. - Observe the traceback. task-5916246 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#249958 Forward-Port-Of: odoo/odoo#248206
CRM lead generation now correctly recognizes when a user has no credits and shows the appropriate credit-related message. This avoids misleading users into thinking their filters caused no results when the real issue is insufficient credits.
Original PR description
Before this commit, when the user uses CRM to generate new leads and does not have credits, the error message they would get is "Your request did not return any result (no credits were used). Try removing some filters." This commit fixes this in _perform_request by instead of expecting InsufficientCreditError raised it now expects the credit_error flag to be set. task-5925047 Forward-Port-Of: odoo/odoo#250433
Back-in-stock notification emails now use the email address of the website where the customer requested the alert, instead of the product company's email. This helps ensure customers receive messages from the expected website brand and improves consistency for multi-website businesses.
Original PR description
…notification # The problem The mail sent to notify a customer that a product is back in stock used the e-mail of the company associated with the product. We would rather use the e-mail of the company associated with the website the notification request was done in. This commit aligns versions 18.0+ with what is done on master (https://github.com/odoo/odoo/commit/8ec57b1115a55e8b59db9b8c1e843c6a1c888db3) opw-5868889 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#250593 Forward-Port-Of: odoo/odoo#249299
This update makes a stock inventory test independent from demo data, so automated checks no longer fail when sample lots or serial numbers are installed. It helps keep quality checks stable without changing everyday user behavior.
Original PR description
The `test_lot_search_partner_ids` expects a specific number of lots/SNs to exist in the database in order to ensure its custom `partner_ids` search works correctly. Because of this, the test fails if any lot demo data is installed. Therefore we create all new locations, products, lots and add extra search domain fields to avoid loading any of these demo data. Also add in extra long partner name to avoid conflicts with overlapping demo/test partner names. runbot error: 162921 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#220777
Email Marketing test sends now clean up their related message records properly. This prevents contacts from showing confusing 'This message has been removed' entries in their chatter after a test email is sent.
Original PR description
**Steps to reproduce:** - Go to Email Marketing app - Create a mailing campaign - Set its recipients to Contact - Click on the test button to send a test mail to any mail - Go to the first contact…
**Steps to reproduce:**
- Go to Email Marketing app
- Create a mailing campaign
- Set its recipients to Contact
- Click on the test button to send a test mail to any mail
- Go to the first contact record
- Chatter will show `This message has been removed` message
**Issue:**
Previously, message created for testing were ignored by the Chatter as they were empty. As we now keep empty messages visible but with removed content display, they shows up on related records.
```py
record = self.env[mailing.mailing_model_real].search([], limit=1)
```
**Fix:**
Ensure the related messages are unlinked at the same time as the test mail in `send_mail_test` by setting `is_notification` to `False` to trigger the `unlink` logic.
```py
def unlink(self):
# cascade-delete the parent message for all mails that are not created for a notification
mail_msg_cascade_ids = [mail.mail_message_id.id for mail in self if not mail.is_notification]
res = super(MailMail, self).unlink()
if mail_msg_cascade_ids:
self.env['mail.message'].browse(mail_msg_cascade_ids).unlink()
return res
```
related: https://github.com/odoo/odoo/commit/21f92550f83cbd38df2c223c65c61bd16dc8e2b0
opw-5502787
Forward-Port-Of: odoo/odoo#247805This update resolves an issue where a 100% discount on German Point of Sale (POS) certified orders would cause an error. The fix ensures the system correctly handles maximum discounts, preventing disruptions to order processing and improving accuracy for German businesses using this module. This change was backported from a previous fix.
Original PR description
Backport of https://github.com/odoo/enterprise/pull/98869 opw-5240429 Forward-Port-Of: odoo/enterprise#108561
This update resolves an issue where certain Intrastat codes (99450000, 99500000, 99600000 & 99700000) were incorrectly marked as expired. The fix ensures these codes remain active, aligning with official Belgian regulations outlined in the Intrastat manual. This correction is crucial for accurate reporting of international trade data.
Original PR description
99450000, 99500000, 99600000 & 99700000 were erroneously expired. They are still active : https://www.nbb.be/doc/dd/onegate/data/intrastat_manual_basis_en.pdf page 13 Forward-Port-Of: odoo/enterprise#108451
This update fixes an issue where VAT amounts were incorrectly displayed as zero in XML exports for manual journal entries. The fix removes a filtering condition that was excluding standard journal entry lines from VAT calculations, ensuring accurate VAT reporting in the tax reports. This improves the reliability of financial data exports.
Original PR description
## Issue: When creating a manual journal entry with a deductible tax, the entry was included in the XML export, but the VAT amounts were all set to 0 ## Cause: The SQL query used to compute VAT amounts included an extra condition on display_type to be 'tax' However, journal entry lines are standard product lines and should not be excluded by this condition As a result, the amounts (MHT, TVA, TTC) were incorrectly computed as 0 in the XML ## Steps to reproduce: - Install `l10n_ma_reports` and switch to the MA Company - Create a Journal Entry (Any account, Debit: 100, Taxes: 10% 150) - Open the Tax Report for the current month - Export the XML using the gear icon Before the fix, the value for mht, tva and ttc where all 0 opw-5226529 Forward-Port-Of: odoo/enterprise#108644
This update ensures that check printing in the Philippines accurately reflects the net payment amount after withholding taxes. Previously, the check amount didn't correctly account for these deductions. A new test case has been added to verify this updated behavior.
Original PR description
In Philippines' check localization module, the amount on check should be based on the net amount after deducing withholding amount for payments if the payment is with taxes that are set as withholding on payment. This commit fixes the check print's values to reflect the net amount. Minimal test case is also added to safeguard the new behavior. [Task-5928813](https://www.odoo.com/odoo/all-tasks/5928813) Forward-Port-Of: odoo/enterprise#108611
This update fixes an issue where SII invoices weren't correctly formatted, preventing successful submission. The change updates XML tags related to withholdings in the DTE template to align with SII's specifications. This ensures invoices are properly processed and accepted by the SII system.
Original PR description
Link to SII API Documentation: https://www.sii.cl/factura_electronica/formato_dte.pdf Problem: The DTE template was using incorrect XML elements for withholdings when confirming an invoice with SII. This fix replaces: ImptRetOtrMnda -> ImpRetOtrMnda ValorImpOtrMnda -> VlrImpOtrMnda so the generated DTE matches SII specifications. OPW-5437484 Forward-Port-Of: odoo/enterprise#105152
This update corrects a bug where the 'Publish & Send' button was hidden in the 'Schedule by Resource' view. The previous fix incorrectly added a context variable, leading to this issue. This change removes the problematic condition, restoring the button's visibility and functionality.
Original PR description
## Issue Since commit https://github.com/odoo/enterprise/commit/a0f44c2bdb2, `planning_test_tour_no_email` is failing when trying to click on the (missing) `Publish & Send` button. ## Cause The…
## Issue
Since commit https://github.com/odoo/enterprise/commit/a0f44c2bdb2, `planning_test_tour_no_email` is failing when trying to click on the (missing) `Publish & Send` button.
## Cause
The commits adds the `my_planning_action` attribute to the context when opening the `Schedule by Resource`. This allowed to display the `I Take It!` button when opening an open shift, but it also removed the `Publish & Send` button, as its condition to be invisible consistently contains `context.get('my_planning_action')` [[1](https://github.com/odoo/enterprise/blob/6892fbda8717effdf3eac06eb6783f1c238ce789/planning/views/planning_views.xml#L11), [2](https://github.com/odoo/enterprise/blob/6892fbda8717effdf3eac06eb6783f1c238ce789/planning/views/planning_views.xml#L78-L79), [3](https://github.com/odoo/enterprise/blob/6892fbda8717effdf3eac06eb6783f1c238ce789/planning/views/planning_views.xml#L273-L274)].
## Fix
The objective is to fix the bug from previous commit https://github.com/odoo/enterprise/commit/a0f44c2bdb2 differently. Instead of adding the `my_planning_action` to the context, we remove the conditions on the `I Take It!` button.
runbot-241028
Forward-Port-Of: odoo/enterprise#108333This update resolves an issue where the 'Request Signature' option wasn't consistently appearing in the cog menu on certain forms (like Timesheets and Projects). The fix ensures the menu item only displays when a chatter is present, improving the user experience and preventing confusion.
Original PR description
****Behavior:**** **Current:** When selecting the cog menu on certain forms, the request signature item doesn't always show even though it should. The expected behavior of this menu item is to appear only on form views with a chatter, but the way the chatter's presence was verified is inconsistent. **Solution:** On form views with a chatter, we can check its presence directly from the viewArch using the selector from the compiler registry. **Steps to reproduce:** From Timesheets: - Go to Timesheets - Open a task - The cog menu will not contain "Request Signature" From Project: - Go to Project - Select a project and open a task - The cog menu will contain "Request Signature" opw-4817423 Forward-Port-Of: odoo/enterprise#107299 Forward-Port-Of: odoo/enterprise#97401
A recent bug in web studio prevented users from correctly saving approval domain rules, specifically when using the 'not set' operator. This issue stemmed from how the system was converting domain data between Python and JavaScript. The fix ensures that domain data is properly formatted for use in the web studio interface, resolving this limitation.
Original PR description
Steps to reproduce ================== - Install web_studio,sale_management - Open a form view in sale - Open studio - Click on the "Send by email" button - Add an approval rule - Add a domain by clicking on the filter icon - Use the not set operator - Confirm - Click on the filter icon again - Confirm => ValueError: malformed node or string on line 1: <ast.Name object at 0x79ff4c7b7f50> Cause of the issue ================== JSON.stringify was used to pass the domain as a string to the DomainSelectorDialog. This doesn't work for boolean as they don't have the same representation in JavaScript as opposed to Python. Solution ======== Use the Domain().toString function opw-5923585 Forward-Port-Of: odoo/enterprise#108350 Forward-Port-Of: odoo/enterprise#107432