Daily updates from Odoo
Friday, July 10, 2026
26 changes · 19.0
Security fixes and vulnerability patches
Database API keys are now better protected from accidental or unauthorized exposure. The key is no longer sent to the user interface and is masked when entered, reducing the risk of sensitive credentials being leaked.
Original PR description
The aim of this commit is to harden the security of the `database_api_key` field. Before this commit: The field could be retrieved through the orm and could be leaked if the access rights were bypassed. A streamer pasting the key in the field could also leak his api key by mistake. After this commit: The only way to access the field is through direct SQL access. The api key isn't shown anymore in the UI: - The UI doesn't receive the key from the backend: it receives dummy **** - The field in the form view display dots instead of any char to prevent leaking the key by mistake. Task-id: None
New functionality added to Odoo
This change adds a migration bridge to help Belgian point-of-sale deployments move from the older fiscal device module to the newer version. It reduces migration friction for businesses that must keep POS operations compliant while upgrading.
Original PR description
This commit adds a bridge module between the two belgian FDM modules to ease the migration from v1 to v2.
Odoo now supports WhatsApp's new business-scoped user IDs, so businesses can keep matching and contacting customers even when WhatsApp no longer shares a phone number. It also stores WhatsApp's standardized phone identifier to improve contact matching across different phone number formats, and avoids crashes when WhatsApp error messages are processed.
Original PR description
Add support for whatsapp business-scoped user ids as outline in the [documentation](https://developers.facebook.com/documentation/business-messaging/whatsapp/business-scoped-user-ids) for their introduction this June. This effectively adds a table mapping BSUID to contacts to enable contacting users who contact the business directly, as the business will now not necessarily be provided with their number. Additionally the “whatsapp id”, i.e. the canonical form of the phone number as stored in whatsapp, is stored to help better match contacts regardless of formatting details in odoo and whatsapp. task-5476552 Forward-Port-Of: odoo/enterprise#117782
Enhancements to existing features
The bank reconciliation widget now loads less data and shifts some heavy calculations away from the browser. This should make opening reconciliation screens faster on very large databases, improving day-to-day accounting workflows.
Original PR description
When opening the bank rec widget on huge DB's, it takes
a lot of time to load everything.
This commit aims to improve the loading performances by
removing some JS fields:
1 - reconciled_lines_ids: We only use the first element of
this recordset in JS, so we add a new computed field
to only send 1 record to the JS
2 - hasAttachment: replace the long JS computation of
`get hasAttachment` with a python computed field.
3 - Replace matched_credit_ids and matched_debit_ids
with exchange_diff_partial_ids.
Linked:https://github.com/odoo/odoo/pull/269119
task-6275945Loss amounts in the Lithuanian Profit and Loss report are now displayed in red instead of grey with only a negative sign. This makes negative results more visible and helps users review financial performance more quickly.
Original PR description
Before this commit: - The losses in the Lithuanian P&L report are shown in grey with only a -ve sign After this commit: - The losses in the P&L report are shown in red now. Related PR: https://github.com/odoo/odoo/pull/239388 Task-5269617
Attachment deletion is now much faster for companies using the Chilean electronic invoicing and stock localization features. The change improves database lookup performance, reducing delays when deleting many attachments in large databases.
Original PR description
## The problem Deleting attachments checks foreign key triggers. Lookups in `account_move` and `stock_picking` tables for `ir_attachment` related fields coming from `l10n_cl_edi` overrides were slow due to missing indexes. ## The solution Added needed indexes to optimize triggers' lookups. ## Benchmark Time benchmark (deleting attachments from a customer database with 224K account moves and 204K stock pickings): |# of rows|Time (Before)|Time (After)| |----------|--------------|-------------| 100 | 29s | 16ms 1000 | 285s | 300ms OPW-6331845 Forward-Port-Of: odoo/enterprise#123350 Forward-Port-Of: odoo/enterprise#123252
Resolved issues and error corrections
Financial reports now handle “load more” results correctly when grouped by account and partner. This prevents duplicate Unknown entries, missing partners, and an error when opening the trial balance, helping users trust report results and avoid interruptions.
Original PR description
**Commit 1** [FIX] account_reports: sorting of lines on load more with unknown record Steps to reproduce: - Create a db with demo data - Open the balance sheet's configuration menu. - Set a groupby key of the "Bank and Cash" line to "account_id,partner_id" - Set a load_more limit to 2 for the report - Open the report and unfold the "Bank and Cash line", and load more multiple times. -> The "Unknown" line is displayed several times, while "LightsUp" partner is missing. This is because we removed one record from the sorting if the "load more" line was still necessary. However, it only needs to be the case if no "Unknown" partner is used since this one will always be the last. **Commit 2** [FIX] account_reports: fix load more on trial balance Steps to reproduce: - Set a load more limit on the trial balance and define a grouping key "account_id, partner_id" - Open the report -> Traceback, because the load more line has empty lists in the "columns" key.
Point of Sale receipts will no longer include the extra terminal receipt text from Worldline payments. This keeps customer receipts shorter, clearer, and avoids duplicate or unnecessary payment information.
Original PR description
This PR removes the terminal receipt from Worldline we are currently inserting in the Point Of Sale receipt We don't adapt the driver code to get the receipt as we cannot change C method prototypes task-6373975
Czech VAT control statements now place invoices from partners with non-domestic VAT numbers in section A5 instead of A4. This helps keep tax reports compliant by ensuring A4 is reserved for domestic VAT transactions only.
Original PR description
With l10n_cz company: - Create an invoice for a partner with a foreign vat (EU) with an amount greater than 10000 CZ and a 21% tax. In the vat control statement of the tax report, the move is classified under A4. But the section A4 should only contain move with domestic vat opw-6268506
Canadian check printing now hides check numbers on the attached stubs when pre-numbered checks are used. This keeps the printed check and its stubs consistent and avoids duplicate or confusing numbering on payment documents.
Original PR description
The check itself respected the check_manual_sequencing field, but the stubs did not. Hide the numbers on stubs as well, exactly like on US checks. task-6343701 Forward-Port-Of: odoo/enterprise#122565
The Colombian DIAN invoicing module now correctly hides the Reset to Draft option for credit notes that have already been accepted by DIAN. This helps prevent users from accidentally changing official documents after they have been validated by the tax authority.
Original PR description
Issue: The reset button would still appear for credit notes that were already accepted by the DIAN. Steps to reproduce: Create a credit note, confirm it and send it to DIAN. You will be able to select Reset to Draft even though it shouldn't be possible to convert to draft after accepted by DIAN. Cause: The function to compute if the reset button would appear or not was only taking into account Invoices. Solution: Added credit notes, to the function that verifies if the reset button should appear. opw-6219265
The Trial Balance report no longer breaks when a very low load limit is set. Accounts are now shown immediately instead of being split behind a “Load More” button, making the report more reliable and easier to review.
Original PR description
Steps to reproduce: - Install Accounting module - Accounting > Reporting > Trial Balance > Set `Load More Limit` to `1` - Try to open `Trial Balance` report Traceback: `KeyError: 'column_group_key'` The Trial Balance report was applying the report load more limit when expanding lines grouped by `account_id`. This caused accounts to be loaded in multiple batches and displayed a "Load more" button even though the number of accounts is typically small enough to be loaded at once. Align the behavior with the General Ledger report and with later versions by setting the load-more limit for this grouping to `False`. This ensures that all accounts are displayed immediately when the Trial Balance report is loaded, eliminating the need for a "Load More" button. opw-6255738
The AI website builder now shows the correct preview image for the AI live chat snippet when the related live chat app is not installed. This helps users understand what the snippet will look like before adding or enabling it.
Original PR description
Commit [1] removed the snippet preview since it mismatched the actual result, but it was overlooked that there's another use of this preview. This commit adds an updated image back. [1]: df05441e469157890253b5550b5f8735723b28fb task-6379796
Swedish bank account details are now read using the dedicated clearing number field instead of inferring it from the account number. This improves ISO 20022 payment file accuracy and reduces failures when processing Swedish payments through international banking systems.
Original PR description
Purpose: This fix addresses an issue where Swedish BBAN account numbers were incorrectly parsed due to the bank code being derived from the account number itself. The parsing logic has been updated to use the clearing_number field, ensuring accurate extraction of the bank code and account number. Changes: Utilized the clearing_number field to obtain the bank code. Sanitized and validated both the account number and clearing number. Implemented Luhn checksum validation for 5-digit clearing numbers when required. Ensured consistent return of sanitized bank_code, sanitized account_number, and checksum type. Impact: This update ensures compliance with ISO 20022 standards for Swedish BBAN account parsing, enhancing interoperability with international payment systems.
This change ensures subscription commission tests correctly clear currency rate data across companies when demo data is present. It prevents false test failures and helps keep commission calculations reliably validated.
Original PR description
Steps to reproduce: 1- Initialize a new database with demo data 2- Run the test `test_sub_commission_no_currency_rate` Issue: `AssertionError: 0 != 10 : Regular invoice, 10 percent of 100` Why this happens: The test used to delete all rows in the res_currency_rate table for the current company only. When we load the database with demo data, the query in `_get_subscription_currency_rates` would find entries for the other companies and wouldn't resort to the default. Later when joining, it would find no rates for the current company and the test fails. runbot-243440
Colombian POS sales that include combo products can now be reported correctly to DIAN. The update prevents zero-priced combo parent lines from being sent in the electronic document, avoiding rejected transactions when customers pay by card.
Original PR description
Issue: When ordering through POS combo items won't be accepted by DIAN. Steps to reproduce: Set company to Colombia and activate the DIAN module. Simulate a sell of an combo item with POS. Pay with card. Error will ensue. Cause: The XML sent to DIAN is not accepted because one of the items has 0 price (the combo item). Solution: Not sending lines that are combo items. opw-6232599
Fixed an issue where expanding a Knowledge sidebar article could show only favorited child articles while hiding other children. Users can now reliably see the full article hierarchy without needing to reload the page.
Original PR description
The sidebar always loads the user's favorite articles along with the visible ones, so a favorited article is shown as a root of the favorite tree. When that favorite is also a child of a folded…
The sidebar always loads the user's favorite articles along with the visible ones, so a favorited article is shown as a root of the favorite tree. When that favorite is also a child of a folded article, it gets added to its parent's child_ids in the main tree, even though the parent's other children were not fetched. A folded article only gets its favorited children back from get_sidebar_articles, not its whole child set. When the parent is then unfolded, unfold() only read the children from the database when child_ids was empty. The favorited child already filled child_ids, so the call was skipped and the remaining children stayed hidden until the next reload. unfold() now uses a new children_loaded flag instead of the length of child_ids to decide whether to fetch the children. The flag is set once an article's whole child set is loaded: in loadChildren(), and in loadArticles() for the articles that were unfolded, since those come back with all their children. loadChildren() also rebuilds child_ids from the search result so a favorite already loaded is not added twice. The fix lives in the sidebar component because the partial child_ids only exists on the frontend, get_sidebar_articles already returns the right records. Steps to reproduce: 1. Open the Knowledge app 2. Create an article with two child articles 3. Add one of the two children to your favorites with the star icon 4. Open another article that is not under that parent 5. Fold the parent article in the sidebar, then refresh the page 6. Expand the parent article => only the favorited child is shown under the parent, the other child is missing Ticket [link](https://www.odoo.com/odoo/project.task/6186466) opw-6186466 Forward-Port-Of: odoo/enterprise#118804
Barcode delivery operations now reuse the existing consigned stock owner when scanning eligible products, including products without lot tracking. This prevents duplicate stock records and keeps inventory quantities aligned with the actual owned stock being shipped.
Original PR description
### Steps to reproduce: - In the settings enable: "Storage Locations" and "Consignment" - Create a storable product and put 1 unit in stock with a set owner - Go to the barcode app > Operations >…
### Steps to reproduce: - In the settings enable: "Storage Locations" and "Consignment" - Create a storable product and put 1 unit in stock with a set owner - Go to the barcode app > Operations > Delivery Orders > New - Scan your product and validate #### > The owner was not set on the stock move line so that a new quant was created and updated in stock rather than using the available unit. ### Cause of the issue: The mechanism of prefilling an owner or a package in the barcode app is currently gate-kept behind the existence of a lot name: https://github.com/odoo/enterprise/blob/0be4f71de3420fb9b72fd4e70d48c6cbbbc0ecb4/stock_barcode/static/src/models/barcode_model.js#L1382-L1407 However, the option also make sense for none tracked products. ### Note: Performing the flow form the backend and adding quantity will generate the move line by setting the owner if possible since the quantity of a move is set via the back end, move lines are generated by looking at the existing quant data's: https://github.com/odoo/odoo/blob/5d61c03b33c9a915684dd59656f8be7612956dd1/addons/stock/models/stock_move.py#L2364 https://github.com/odoo/odoo/blob/5d61c03b33c9a915684dd59656f8be7612956dd1/addons/stock/models/stock_move.py#L2328-L2330 Setting the same owner on the new move line as on the quant we are going to reserve: https://github.com/odoo/odoo/blob/5d61c03b33c9a915684dd59656f8be7612956dd1/addons/stock/models/stock_move.py#L2337 https://github.com/odoo/odoo/blob/5d61c03b33c9a915684dd59656f8be7612956dd1/addons/stock/models/stock_move.py#L1715 Additional subtelties appearing when prefilling for non tracked product: 1. Currently the available quantity is not taken into account to determine if the the value provided to the prefilled is actually relevant, in particular if there is a quant with an available quantity of 0, it will be used as a valid value to prefill and it will parasit the prefill that could be done by other quants. 2. The location source used to determine the quants taken into account is not set on the first scan since the scan is performed without any existing line: https://github.com/odoo/enterprise/blob/4f0d25f9fe4ca8ff1b0ecd7900899a2a246ba888/stock_barcode/static/src/models/barcode_model.js#L1387 > This was not problematic with respect to tracked product since the product needs to be scanned prior to the lot, hence there is always a current line when the the lot is scanned. opw-6050657 Forward-Port-Of: odoo/enterprise#122998 Forward-Port-Of: odoo/enterprise#115021
This fix ensures status messages in French reporting are displayed properly when documents are accepted or rejected. It prevents error details from appearing incorrectly, helping users understand report outcomes without confusion.
Original PR description
A mismatch between error titles and status logs was introduced in 18.0. Markup wasn't added to the status logs, leading to a type mismatch (Markup + str) when displaying errors for 'accepted' or 'rejected' statuses. As a result, the logs were not interpreted as HTML. This commit ensures Markup is applied to each element to guarantee coherence and proper rendering. backport of 5113752 task-6053842 Forward-Port-Of: odoo/enterprise#123250
Fixed an issue in the Barcode app where scanning both individual items and packaged quantities could save the wrong total after leaving and reopening a delivery. This prevents undercounted quantities during validation and helps keep inventory and delivery records accurate.
Original PR description
### Steps to reproduce * Enable the Units of Measure setting and create a packaging UoM for a product (e.g. "Pack of 10"). * Create a customer delivery for that product and confirm it. * Open the…
### Steps to reproduce * Enable the Units of Measure setting and create a packaging UoM for a product (e.g. "Pack of 10"). * Create a customer delivery for that product and confirm it. * Open the picking in the Barcode app, scan the product unit barcode once, then scan the packaging barcode once. * Exit the barcode app via the back arrow (without validating). * Re-open the picking and validate it. **Expected**: `move.quantity` reads `11` (1 unit + 1 pack of 10). **Observed**: `move.quantity` reads `2` (the raw count of move lines), while the detailed move lines still show 1 unit and 1 pack of 10. ### Cause On exit, `BarcodePickingModel._onExit` aggregates `qty_done` and `reserved_uom_qty` across the move lines and forwards the totals to `stock.move.post_barcode_process` -> `_truncate_overreserved_moves`. The aggregation ignored each line's own UoM, so a line in a packaging UoM (e.g. pack of 10) was counted as `1` instead of being converted to the move's UoM. `_truncate_overreserved_moves` then saw the real `move.quantity` (11, correctly computed from the move lines) as exceeding what the user supposedly did (2) and forcibly wrote `move.quantity = 2`. The accompanying `_set_quantity` runs with `unreserve_unpicked_only=True` and therefore skips the picked lines, leaving the move lines intact but `move.quantity` stuck at the wrong value through the validation that follows. ### Fix Convert each line's quantity to the move's UoM (using the cached `uom.factor`) before aggregating in `_onExit`. `product_uom` is added to `stock.move._get_fields_stock_barcode` so the move's UoM is available in the client-side cache. ### Why 19.0 only In 18.0 and earlier, scanning a packaging multiplied the scanned quantity in the **product's** UoM (`_retrievePackagingData` returned `quantity = barcodeData.packaging.qty` with `uom = product.uom_id`), so the resulting move lines were all in the same UoM and the raw aggregation was correct. In 19.0 the packaging rework made the scan create a move line in the **packaging's** UoM with `quantity = 1`, which exposed the missing conversion in `_onExit`. ### Test `test_scan_packaging_on_picking_with_mixed_uom` is extended with a 5th receipt that scans 1 unit + 1 pack of 6, exits via `button.o_exit`, re-opens the picking and validates. Without this fix the assertion `quantity == 7.0` fails (truncated to 2).
This fix ensures database API keys are accessed correctly during database management and synchronization workflows. It helps prevent access issues in user management and sync operations, improving reliability for teams managing databases.
Belgian POS Blackbox receipts and menus now show the required FDM and POS software version details again. This helps businesses keep receipts and point-of-sale identification aligned with compliance expectations and improves visibility during audits or checks.
Original PR description
- store the FDM software version on the order and print both `fdmSwVersion` and `posSwVersion` on the receipt - show POS ID and POS software version in the navbar burger menu - assert the restored fields in the blackbox oracle tour Task-id: 5864870
The Argentine VAT Book export now handles foreign partners marked as overseas providers without blocking the ZIP download. This avoids manual workarounds and lets businesses correctly generate VAT reports for transactions involving foreign suppliers or partners.
Original PR description
Steps to reproduce: - Create a partner with: - State: Ireland - Identification Number: Foreign ID 55000004153 - ARCA Responsibility Type: Proveedor del Exterior - Create an invoice for the partner - Accounting > Reporting > Tax report - Select Report: VAT Book (AR), Tax Type: Sales - Click on gear icon > VAT Book (ZIP) Issue: Action will be blocked with error "No VAT configured for partner [58] <partner>" Analysis: Partners with ARCA responsibility type 'Proveedor del Exterior' (code 8) and a ForeignID identification type, causes a UserError when exporting the VAT Book (ZIP). Code 8 (foreign provider) is the purchase-side counterpart of code 9 (foreign customer), which already fell back to the country-level VAT. Extend the existing fallback branch to cover both codes. opw-6316008 Forward-Port-Of: odoo/enterprise#123506
The appointment booking page now keeps month navigation aligned with the first actually bookable slot. This prevents customers from seeing empty months when availability exists, improving booking reliability for appointment-based businesses.
Original PR description
On the website booking page, moving to a later month can show no available times even though the weekly schedule clearly has some. ### Steps to reproduce - Install Appointments. - Create a recurring…
On the website booking page, moving to a later month can show no available times even though the weekly schedule clearly has some. ### Steps to reproduce - Install Appointments. - Create a recurring appointment type available on a single weekday (say Monday), with a user or resource assigned and a date range spanning a few months. - Set `Allow bookings at least` (the minimum booking delay) so that the current time plus the delay falls after this month's last Monday. Close to the end of a month, a day or two of delay is enough. - Open the booking page: the first month shown is next month, because the delay skipped this month's last slot. - Click the arrow to move forward one more month. => the reached month shows no slots, even though it has Monday availability. ### Cause The calendar computes availability one month at a time. It builds a list of months, and the browser refers to each month by its position in that list (0, 1, 2, ...). Clicking the next arrow sends that position back to the server. The server turns the position into a real month by adding it to a start month, which it computes as `now` plus the minimum booking delay. But the list shown to the visitor does not start there: it starts at the month of the first slot that can actually be booked. These two are usually the same, so the position lines up. They stop matching when the delay moves the earliest bookable time past the last availability day of the current month. In the steps above, `now` plus the delay lands after the month's last Monday, so the first bookable slot is a Monday in the next month. The visitor's list then starts one month later than the server assumes, every position points one month too early, and the server computes availability for a month the visitor is not looking at. The reached month comes back empty. ### Fix Count the visitor's month position from the same first bookable slot the list starts from, instead of from `now` plus the delay. The navigation offset is passed to the slot computation and resolved against that slot, so the filled month always matches the month the visitor sees. opw-6353569
This fixes an issue where the Sign app could fail when loading signing fields in debug mode. The change makes the page ignore hidden template comments so users and testers can continue working with documents without interruption.
Original PR description
Use lastElementChild when retrieving the sign item from the target element. In debug mode, inherited templates may introduce HTML comments into the DOM. Since lastChild return a comment node, accessing classList on the returned node raises an error. Using lastElementChild ensures that the last HTML element is always retrieved, regardless of comment nodes in the DOM.
The POS now loads only the Kenyan e-invoicing classification records that are actually used by available products. This avoids pulling unnecessary data into POS sessions, helping improve loading efficiency without changing cashier workflows.
Original PR description
Before `product.unspsc.code` and `l10n_ke_edi_oscu.code` records were loaded without domain, which could lead to loading all records of these models in POS, which is not necessary. This commit adds a domain to the loading of these records, so that only the records that are actually used in the products are loaded in POS.