Friday, July 10, 2026
16 changes · saas-19.3
New functionality added to Odoo
Odoo now supports WhatsApp business-scoped user IDs, allowing businesses to identify and contact customers even when WhatsApp does not provide their phone number. The update also stores WhatsApp’s canonical phone identifier to improve contact matching despite formatting differences.
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
This update introduces support for Georgian accounting standards, including a new chart of accounts, tax settings, and VAT reporting capabilities. This expansion allows Odoo users operating in Georgia to comply with local accounting and tax regulations, streamlining their financial processes.
Original PR description
[ADD] l10n_ge: add Georgian Chart of Accounts - This commit adds the Georgian accounting localization, including the chart of accounts, taxes, fiscal positions, tax groups, and VAT report required for standard accounting and tax reporting flows - It provides support for domestic VAT, reverse charge VAT, and the Georgian VAT declaration report. taskID-3927928 related PR (from 19.0 to saas-19.2) - https://github.com/odoo/odoo/pull/263452
Enhancements to existing features
Attachment deletion is now much faster for companies using Chilean electronic invoicing and related stock flows. This improves responsiveness and reduces delays when cleaning up or processing large numbers of documents.
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
Bank reconciliation entries using tax-based models now show the correct tax base amount immediately. This prevents accounting reports and journal entry reviews from displaying misleading zero base amounts until a manual reset is performed.
Original PR description
### Steps to reproduce the issue: 1. Download Accounting 2. Go to Journal entries and create a new one 3. Click Toggle Studio button and go to the view to add the tax_base_amount field to the list of…
### Steps to reproduce the issue: 1. Download Accounting 2. Go to Journal entries and create a new one 3. Click Toggle Studio button and go to the view to add the tax_base_amount field to the list of existing fields 4. Add 2 lines (example): 1. account Product Sales with 1000 dollars credit and 15% tax under Tax column 2. account Bank with 1000 dollars debit 5. Go to Dashboard > Bank > Click the 3 dots of one random bank matching line and click on Manage Models 6. Go to bank fees and add the 15% tax 7. Go back to bank reconciliation and create a new one of 2000 dollars with label bank fees (it will associate the tax automatically) 8. Go back to Journal Entries, group by Journal and search for the transaction of 2000 sollars for account Bank 9. Problem: see that the Base Amount for the 15% bank fees lines (251000 Tax Received account) is 0. Clicking on Reset to draft button the base amount column is automatically updated but this should happen automatically ### Cause of the issue: This occurs because the _lines_prepare_tax_line method in account.bank.statement.line fails to map this field in its return dictionary. ### Reason to introduce the fix: Currently, when applying a reconciliation model with taxes the generated tax lines incorrectly record a tax_base_amount of $0.00. Instead, it should be displayed and calculated. opw-6220948 Forward-Port-Of: odoo/enterprise#123603 Forward-Port-Of: odoo/enterprise#122139
This update introduces a manual KYC (Know Your Customer) process for Odoo users utilizing the PEPPOL accounting module. Previously, PEPPOL account setup was automated. Now, users can complete a manual verification process, ensuring compliance with PEPPOL regulations and improving data security. This change enhances the reliability and security of transactions within the PEPPOL ecosystem.
Original PR description
Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275371
The Barcode app now respects operation settings that block extra products, even after all reserved items have been scanned and the transfer is reopened. This prevents warehouse users from accidentally adding unplanned products to restricted transfers, improving inventory accuracy.
Original PR description
# How to reproduce - Go to Inventory > Settings > Operation Types - Pick any Operation and disable "Allow extra product" - Create a picking for that operation type with atleast one product and click…
# How to reproduce - Go to Inventory > Settings > Operation Types - Pick any Operation and disable "Allow extra product" - Create a picking for that operation type with atleast one product and click on "Mark as Todo" - Go to the Barcode app and find the created picking - Scan all the reserved products - Exit the picking and re-enter # The problem The "Add Product" button is displayed and you can scan unreserved products even tough you sould not be allowed to # Cause of the issue The problem stems from the fact that even with "Allow extra product" disabled, we still allow to add unreserved products for immediate transfers (created directly in the barcode app). The issue is that we don't really have a way to distinguish immediate transfers from plannified ones made in the Inventory app. So we try to guess using the `_useReservation` attribute (If it is false, we allow additional products). `_useReservation` is computed as follows : if any move lines from the inital state is not yet picked, set it to true : https://github.com/odoo/enterprise/blob/ca4b369e4fc9f4655574cf1ca71c81faaadc3e88/stock_barcode/static/src/models/barcode_picking_model.js#L43 So in our case, once all the reserved products are scanned, all the initial move lines are picked and our guessing fails. # Proposed Solution Since immediate transfers are never validated and stays in draft mode, guess using the state of the current picking in addition to `useReservation` opw-6231238 Forward-Port-Of: odoo/enterprise#118378
Czech VAT control statements now place invoices for customers with foreign VAT numbers in the correct section. This prevents non-domestic transactions over 10,000 CZK from being reported as domestic, improving tax report accuracy and compliance.
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 Forward-Port-Of: odoo/enterprise#120002
Instagram image posts are now handled more reliably when Instagram takes too long or hits a network problem while fetching the image. Instead of causing a server error, the post is marked as failed with a clearer message, helping users understand what went wrong and what to try next.
Original PR description
Making an Instagram containing an image can crash the server with an unhandled `ReadTimeout` instead of marking the post as failed. ### Cause When creating a media container, Odoo passes a URL pointing to its own server and Instagram fetches the image from it server-side before responding. The timeout therefore covers network latency, Instagram's download speed from the Odoo server, and image processing time, making it prone to being exceeded. When it is, `requests` raises a `ReadTimeout` which is unhandled, leading to a raw RPC error instead of a clean `state='failed'`. ### Fix Catch the network errors and mark the post as failed instead of letting them crash the request. Timeouts get a message suggesting a smaller image, since they are usually caused by Instagram fetching and processing a large image server-side. Any other request error falls back to a generic message. opw-6015997 Forward-Port-Of: odoo/enterprise#112573
Employees and managers can now request an appraisal even when the next appraisal date has already passed. This removes an unnecessary error that blocked users who could not manually change appraisal dates, making delayed appraisal workflows smoother.
Original PR description
# How to reproduce You need to simulate the fact that you are creating an appraisal late so either : A) Directly edit the `next_appraisal_date` in SQL B) Go to Employee App > any Employee > Settings,…
# How to reproduce You need to simulate the fact that you are creating an appraisal late so either : A) Directly edit the `next_appraisal_date` in SQL B) Go to Employee App > any Employee > Settings, set Next Appraisal Date to tomorrow and wait for 2 days Then : - Click on Request Appraisal - Save # The problem An error is shown saying "You cannot set 'Next Appraisal Date' in the past.". You can workaround this by changing the Next Appraisal Date to a date in the future, but the problem is not every user has the right to do this. # Cause `next_appraisal_date` is also defined in hr.appraisal as a relate field of hr.employee : https://github.com/odoo/enterprise/blob/0226ad15abc8db70f8e379fddec3d83d15749c85/hr_appraisal/models/hr_appraisal.py#L56-L57 When creating an hr.appraisal, `next_appraisal_date` is present in `vals_list` because it is defined in the view since : https://github.com/odoo/enterprise/commit/58fba3098f33db82dfbccca2db229550402ed3ab https://github.com/odoo/enterprise/blob/0226ad15abc8db70f8e379fddec3d83d15749c85/hr_appraisal/views/hr_appraisal_views.xml#L92 This triggers a write on `next_appraisal_date` of hr.employee which triggers a constraint : https://github.com/odoo/enterprise/blob/0226ad15abc8db70f8e379fddec3d83d15749c85/hr_appraisal/models/hr_employee.py#L81-L85 opw-6147865 Forward-Port-Of: odoo/enterprise#122440 Forward-Port-Of: odoo/enterprise#114876
Fixed an issue where expanding a folded Knowledge article could show only favorited child articles while hiding other children. Users can now reliably see the full article hierarchy in the sidebar without needing to reload.
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
Belgian certified POS receipts now show the required fiscal device and POS software version information again. This helps businesses using the blackbox setup keep receipts and POS identification aligned with compliance expectations.
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 FW of https://github.com/odoo/enterprise/pull/123839 Task-id: 5864870
This fix prevents an error when validating refunded point-of-sale orders for Kenyan companies using eTIMS/OSCU. Refunds and batches of offline orders can now be processed correctly, reducing checkout disruption and manual follow-up.
Original PR description
Steps to reproduce: 1. Install `l10n_ke_edi_oscu_pos`, set company to Kenya. 2. Sell and validate an order. 3. Refund it from the POS and validate the refund order. Issue: - A traceback is raised…
Steps to reproduce: 1. Install `l10n_ke_edi_oscu_pos`, set company to Kenya. 2. Sell and validate an order. 3. Refund it from the POS and validate the refund order. Issue: - A traceback is raised when validating the refund: `ValueError: Expected singleton: pos.order(<refund>, <original>)` raised in `get_l10n_ke_edi_oscu_pos_data`. Cause: - When syncing a refund, `sync_from_ui` returns both the new refund order and the original refunded order. `waitForPushOrder` forces post-processing for every Kenyan order in that list, so `beforePostPushOrderResolve` receives both ids in `order_server_ids` and forwards them as-is to `action_post_order` and `get_l10n_ke_edi_oscu_pos_data`, both of which expect a single record. `action_post_order` fails the same way, but its error was silently swallowed by the surrounding try/catch, letting the traceback surface only on the second call. - The same multi-id list is also produced whenever several orders created offline get synced together once back online. Solution: - `get_l10n_ke_edi_oscu_pos_data` is only needed for the receipt of the order being validated, so call it with `order.id` instead of the full `order_server_ids` list. - Replace the `action_post_order` call with `action_post_selected_orders`, which posts each order individually and skips ones already sent to eTIMS, correctly handling both the refund case (original order is already `sent`) and the offline multi-order sync case. opw-6364221 Forward-Port-Of: odoo/enterprise#123043
This update fixes cases where the social feed action menu appeared empty, improves reliability when refreshing feeds by allowing longer batch requests, and resolves LinkedIn image upload failures. These changes help social media users manage posts and leads more smoothly with fewer interruptions.
Original PR description
Bug 1 === Since b75755ea8ac65ce5ce973412e3c4194fa1bd6fd3 , the menu on the stream post could be visible but empty. The reason is that we checked for `this.isConvertibleToLead` instead of `this.isConvertibleToLead()`. We take advantage of this bug fix to correctly overwrite the condition without replacing the entire button (which can break other module overwriting the same element). Bug 2 === Sometimes, when refreshing the feed view, an error occurs because the request timeout. To fix it, we increase the timeout when doing requests in batch. Bug 3 === When uploading an image in LinkedIn, an error happens. The reason is that `LocalBinaryFile` is now returned when reading Binary field, and in the requests API, the `data` arguments expect the bytes. (for other media, we upload the image with `file` argument). Task-6254983
Appointment blocks using picture or list layouts now show prices according to the website's tax display setting. This prevents customers from seeing tax-excluded prices when the site is configured to show tax-included prices.
Original PR description
When the `appointments_template_picture` and `appointments_template_list` templates were added to `website_appointment_account_payment` in 19.0+, the corresponding overrides in `website_appointment_sale` were not added. This caused the picture and list appointment blocks to display prices using `product_lst_price` (always tax-excluded), ignoring the website's tax display setting (`show_line_subtotals_tax_selection`). The cards template already had a proper override using `_get_combination_info()`, which correctly handles everything. Steps to reproduce: 1. Go to Website > Configuration > Settings > enable "Tax Included" 2. Create an appointment type with a product that has taxes 3. Edit website page > add "Appointments" snippet > select "Picture" or "List" layout => price shown is tax-excluded Ticket [link](https://www.odoo.com/odoo/project.task/5799252) opw-5799252 Forward-Port-Of: odoo/enterprise#106643
The Argentine VAT Book ZIP export now handles foreign provider partners correctly. This prevents exports from being blocked by a missing VAT error, helping accounting teams complete required tax reporting for transactions with foreign 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
This update resolves an issue where sales orders could incorrectly show analytic distributions exceeding 100%, leading to confusing accounting reports. The change consolidates analytic distributions from multiple models into a single line, maintaining functionality while ensuring accurate reporting. This improves clarity and prevents potential over-allocation of costs.
Original PR description
Steps: 1. Create an analytic model filtered by partner. 2. Create an analytic model filtered by product. 3. Create a project with an analytic distribution. (Make sure the distributions use different plans) 4. Create an SO for a product within the project that both the models apply to. 5. Confirm the SO. 6. Notice the analytic distribution for the project account is at 200%. When an SOL is created, the analytic distribution from each model is added as a separte line The analytic account for the project is added to each analytic distribution line. This can easily cause the account to have >100% distribution for a given SOL. This is unintuitive and confusing behaviour. This PR changes the behaviour to only create one line for all the distributions from analytic models. This should prevent this behaviour while keeping the functionality of applying the project distribution to each line. opw-6250908 / opw-6304033 Forward-Port-Of: odoo/odoo#270151