Thursday, May 28, 2026
14 changes · 19.0
New functionality added to Odoo
This pull request updates the `.weblate.json` files used for translating Odoo's Belgium Point of Sale (POS) modules. It ensures that all necessary modules are included for accurate translation, improving the user experience for customers using the system in Belgium. This is a routine maintenance update to support localization efforts.
Original PR description
Add missing modules in `.weblate.json` for translations of (l10n_be_pos_blackbox, l10n_be_pos_blackbox_hr, l10n_be_pos_blackbox_loyalty, l10n_be_pos_blackbox_self_order, l10n_be_pos_blackbox_settle_due) These modules were added in this PR: https://github.com/odoo/enterprise/pull/96130
Enhancements to existing features
This change adds a safe customization point for how small rounding differences are handled on invoices with tax excluded from prices. Standard behavior stays the same, while country-specific accounting rules can keep product line subtotals aligned with their accounting balances when required.
Original PR description
## Context Forward-port to `19.0` of #266748 (proposal 1/2). Follow-up to issue #266745. opw-6177008 **Default behavior unchanged** (`True` returned). The hook is meant to be overridden in localizations where the contractual truth is the HT per line (typical B2B accounting in France, Belgium, etc.), preserving `price_subtotal == balance` on every product line. A mirror JS helper `should_distribute_base_delta_for_excluded_mode` is added in `addons/account/static/src/helpers/account_tax.js` to keep python/js consistent. ## Why See #266745 for the full reasoning, numeric example and full anonymized real-world invoice (109 lines). Staging validation: 22 lines with `price_subtotal ≠ balance` without fix → 0 mismatches on 1,175 lines with fix. This PR is **non-breaking**: it just exposes a clean override point. A companion PR provides the override for `l10n_fr_account`. _Closed — forward-port will be auto-created by Odoo CI bot after #266748 is merged._
Resolved issues and error corrections
This change fixes an internal startup error caused by a missing HTML cleaning component in a dependency. It helps ensure Odoo can start reliably in affected environments without crashing during initialization.
Original PR description
still ``lxml.html.clean`` import is needed because ``lxml.html`` init file don't have clean file. So, it will be not loaded For reference :-…
still ``lxml.html.clean`` import is needed because ``lxml.html`` init file don't have clean file. So, it
will be not loaded
For reference :- https://github.com/lxml/lxml/blob/lxml-4.9/src/lxml/html/__init__.py
```
Traceback (most recent call last):
File "/tmp/tmpj23nirpw/odoo/19.0/./odoo-bin", line 3, in <module>
import odoo.cli
File "/tmp/tmpj23nirpw/odoo/19.0/odoo/cli/__init__.py", line 2, in <module>
from .command import Command, main # noqa: F401
File "/tmp/tmpj23nirpw/odoo/19.0/odoo/cli/command.py", line 8, in <module>
import odoo.init # import first for core setup
File "/tmp/tmpj23nirpw/odoo/19.0/odoo/init.py", line 28, in <module>
from .tools.gc import gc_set_timing
File "/tmp/tmpj23nirpw/odoo/19.0/odoo/tools/__init__.py", line 11, in <module>
from .i18n import format_list, py_to_js_locale
File "/tmp/tmpj23nirpw/odoo/19.0/odoo/tools/i18n.py", line 8, in <module>
from odoo.tools.misc import babel_locale_parse, get_lang
File "/tmp/tmpj23nirpw/odoo/19.0/odoo/tools/misc.py", line 40, in <module>
from lxml import etree, objectify
File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
File "/tmp/tmpj23nirpw/odoo/19.0/odoo/_monkeypatches/__init__.py", line 45, in exec_module
patch_module(module.__name__)
File "/tmp/tmpj23nirpw/odoo/19.0/odoo/_monkeypatches/__init__.py", line 67, in patch_module
module.patch_module()
File "/tmp/tmpj23nirpw/odoo/19.0/odoo/_monkeypatches/lxml.py", line 14, in patch_module
lxml.html.clean._find_image_dataurls = re.compile(r'data:image/(.+?);base64,').findall
AttributeError: module 'lxml.html' has no attribute 'clean'
```
https://upgradeci.odoo.com/upgradeci/run/301804
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#266591Users sending invoices through Peppol now receive a more precise message when a customer is missing the required Peppol identifier. This reduces confusion by naming the exact missing field instead of incorrectly suggesting the VAT number is absent.
Original PR description
When a user sends a move via Peppol to a customer that has a VAT number set but not a Peppol endpoint, we show the user a generic error ("no VAT").
This makes the user confused, as he already filled the VAT field of his customer, It's the Peppol VAT that is missing (it could be: Belgian Company Registry, France SIRET, ...etc, depending on the customer's country)
This PR makes the error message more accurate by showing exactly the missing required field.
task-5499707
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#263685
Forward-Port-Of: odoo/odoo#245915Generated PDFs for some vendor bills now consistently show the internal item reference on product lines, even when supplier XML files omit the usual description field. This makes bills easier to identify, review, and match against internal products.
Original PR description
Some XML vendor bills generated by external ERPs were missing the Description tag, which typically contains both the [ITEM_REF] and ITEM_NAME. As a result, product lines in the generated PDF could appear without the internal item reference. This commit ensures that the item reference is always included in the displayed product line. task-6080328 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#259086
This fix prevents customized email marketing access rules from being overwritten during system upgrades. It helps protect customer-specific permission settings and reduces upgrade-related disruption.
Original PR description
`noupdate` flag of `ir.rule` should be equal to true. A client can change the permissions of ir.rule and their changes will be overwritten due to the fact that the `noupdate` flag is currently false. I had an issue with the upgrade of a client DB, because its permissions have been overwritten.
Link preview records now show a friendly label instead of an internal technical reference. New records display as “New,” and saved records use their source URL, making technical administration screens easier to understand.
Original PR description
**Problem:** Opening a new `mail.link.preview` record from the technical view shows the internal record reference (e.g. `mail.link.preview,NewId_0x...`) in the breadcrumb instead of the standard…
**Problem:**
Opening a new `mail.link.preview` record from the technical view shows the internal record reference (e.g. `mail.link.preview,NewId_0x...`) in the breadcrumb instead of the standard "New" label.
**Steps to reproduce:**
1. Settings / Technical / Discuss / Link Previews
2. New
3. Observe the breadcrumb
**Current behavior:**
The breadcrumb displays `mail.link.preview,<id>`.
**Expected behavior:**
The breadcrumb should display "New" until the record is saved, and the source URL once saved.
**Cause of the issue:**
The model defines no `name` field and does not set `_rec_name`, so the default `_compute_display_name` falls into its fallback branch and returns `f"{record._name},{record.id}"` — exposing the technical reference in the breadcrumb both for unsaved records (`NewId_...`) and saved ones.
**Fix:**
Setting `_rec_name = 'source_url'` lets the standard display name machinery compute a meaningful label from the existing required field. Unsaved records then surface the standard "New" placeholder via the web client and saved records surface their URL, without introducing a redundant `name` field or overriding the compute.
opw-6095012
Forward-Port-Of: odoo/odoo#263577The editor toolbar now correctly highlights the text color button whenever the color picker is open. This makes the formatting controls clearer and avoids confusion when users apply text colors.
Original PR description
Problem: The state of the text color button is not synchronized with the color picker state. When the picker is open, the button is sometimes not shown as active. Cause: The `.active` class depends on `colorPicker.isOpen`, which does not trigger a rerender when updated. As a result, Owl does not refresh the button state when the picker opens or closes. Solution: Use a component state for the picker visibility and update it through `onOpen` and `onClose` callbacks so Owl rerenders and properly adds or removes the `active` class. Steps to reproduce: - Select some text and expand the toolbar. - Click the text color button to open the color picker. - Observe that the text color button is not active. - Click on the "Custom" tab in the color picker. - Observe that the text color button becomes active. task-6205286 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Website sidebar menus now allow vertical scrolling when there are more menu items than fit on the screen. This ensures visitors can access all navigation options, especially on pages with many menu entries or limited screen height.
Original PR description
Scenario: - set menu bar as sidebar - adds lot of menu item (or decrease page height) - try to scroll to bottom menu item that are not shown Result: you can't see the bottom of the menu Cause: there is no overflow auto on sidebar elements so the default visible is used without possible scroll. This issue doesn't happen for hamburger menu (hamburger template or on mobile) because it wraps the menu in an .offcanvas-body element that has in bootstrap overflow-y: auto Fix: add vertical overflow to o_header_sidebar menu. opw-5486934 --- __pr note__: I'm not sure if there is a reason this was not done yet or if this has just not been reported. The behavior happen from 16.0 to now. Since the query is from 19.0 to lower risk (and since it's not really broken, just not working with a big number of menu) I've targeted 19.0 but I could go lower if wanted.
Users can now Ctrl-click records from their dashboard to open them in a new browser tab instead of replacing the current page. This fixes dashboard navigation so it behaves as expected and helps users keep their dashboard open while reviewing records.
Original PR description
Steps to reproduce ================== - Install project,board - Go to project - Open any project - Click on the cog menu - Click on Dashboard > Add to my dashboard - Confirm - Open the dashboard app > My dashboard - ctrl+click on a record => The record is opened in the current tab Cause of the issue ================== The params newWindow passed to the selectRecord props was ignored
This update fixes a bug in the attendance tracking system for employees on flexible schedules. The previous test incorrectly assumed contract-based hours should apply, leading to inaccurate overtime/undertime calculations. The changes ensure that overtime/undertime rules are correctly disabled when flexible schedules are in use, aligning with the system's specifications.
Original PR description
Version-19.0 **Issue:** Tests assumed contract-based expected hours would still apply under flexible schedules, but specs state that overtime/undertime defined on the contract should not apply for employees with flexible schedule. ### Summary of Changes The previous test `test_lunch_time_case` still relied on contract-based expected hours under a flexible schedule, causing incorrect assertions. The test is updated to: - enable flexible_hours on the resource calendar, - disable expected_hours_from_contract on the rule, and - define expected_hours explicitly. This aligns the test with the correct behavior and prevents false failures. related-https://github.com/odoo/odoo/pull/236271 task-[5265617](https://www.odoo.com/odoo/action-4043/5265617)
This update corrects a dependency issue within the Italian reporting module (l10n_it_reports). Specifically, a new filter was added to address a conflict related to pension fund types, originally defined in a separate module. This ensures the Italian reporting functionality operates correctly and reliably.
Original PR description
Commit: 0a5657297f312cb3e5f6c3ab6a281acf71fbee3b added a filter for the field l10n_it_pension_fund_type which is defined in l10n_it_edi_withholding and not l10n_it_reports runbot-242217 Forward-Port-Of: odoo/enterprise#113185
This update fixes a problem where bank statement KPIs weren't being updated correctly when no statements were processed. Now, if no KPIs are reported, the corresponding columns are emptied, ensuring accurate KPI tracking within the account module. This prevents potential reporting inaccuracies related to bank statement processing.
Original PR description
The aim of this commit is to update the integer kpis when those aren't received. ### Context: The account module report the bank statement in draft to process. When all bank statement have been processed, there isn't any and thus, the module send back an empty list. ### Before this commit: The bank statement kpi wasn't updated as we didn't received anything about that specific kpi. ### After this commit: Any kpi that wouldn't be reported would get it's column emptied. opw-6170973
This update ensures that payment notifications and receipts are sent to the correct contact – the invoice contact – when a partner has an invoice associated with them. This change aligns with existing practices and improves the accuracy of communication related to payments, while maintaining accounting integrity.
Original PR description
**Context:** Before this commit `account.payment.partner_id` was restricted (by domain) to commercial partners. When a partner has an invoice contact child (`type='invoice'`), checks, receipts and outgoing emails end up addressed to the parent partner instead of the intended invoicing contact. Accounting entries must still be linked to the commercial partner to preserve reporting & reconciliation integrity. **Solution:** The invoice model (`account.move`) already solves the same problem: `partner_id` stores the communication contact, `commercial_partner_id` is the stored compute used for accounting. This commit mirrors that architecture on `account.payment`. Since we are doing this change in stable, we cannot store the commercial partner yet, loosing some out-of-the-box features. We therefore add manual _search. task-6123823