Daily updates from Odoo
Friday, July 10, 2026
54 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
Databases can now show the status of the Know Your Client procedure as a KPI. This helps business users quickly see customer verification progress directly from database information.
Original PR description
Add a new type kyc_status to display the status of the Know Your Client procedure in the databases. Task-id: [6348952](https://www.odoo.com/odoo/project.task/6348952) Forward-Port-Of: odoo/enterprise#122510
backport of 5324615 As in Finland the tax rate will change from 14 to 13.5 on certain goods and services those taxes and the corresponding tax group were added to the l10n task-6332565 Forward-Port-Of: odoo/odoo#274792 Forward-Port-Of: odoo/odoo#274460
Original PR description
backport of 5324615 As in Finland the tax rate will change from 14 to 13.5 on certain goods and services those taxes and the corresponding tax group were added to the l10n task-6332565 Forward-Port-Of: odoo/odoo#274792 Forward-Port-Of: odoo/odoo#274460
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
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 change corrects outdated internal field references in the POS pricer module after a previous rename. It prevents installation failures when demo data is loaded, helping ensure smoother setup and testing of the module.
Original PR description
The field `pricer_product_to_create_or_update` was renamed to `needs_pricer_update` in the following upgrade commit: https://github.com/odoo/upgrade/commit/bda95f88a6e644bb18b5669ef1a23d49a0111f00 However, two instances were missed in `account_tax.py` and `product_supplierinfo.py`. This caused tracebacks during module installation when loading demo data. Task [link](https://www.odoo.com/odoo/project.task/6373263) task-6373263 Forward-Port-Of: odoo/enterprise#123698
Expense creation from documents now works for authorized users even when their account is not linked to an employee profile. This removes an unnecessary blocker while still requiring the proper permissions to create expenses for other employees.
Original PR description
Removes the constraint saying a user has to be linked to an employee to create an expense from a document. In this case, the user still needs the rights to create an expense for another employee. task-6237021 Forward-Port-Of: odoo/enterprise#123635 Forward-Port-Of: odoo/enterprise#118955
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
The tax return validation test was adjusted to avoid running the real PDF rendering step during automated browser testing. This prevents intermittent connection errors in test runs, helping keep release validation reliable without changing the user-facing tax return workflow.
Original PR description
Validating a return renders the report to a PDF via wkhtmltopdf inside the `action_validate` request. During the render, the HttpCase test cursor is reserved for wkhtmltopdf, so any browser RPC that overlaps the render window is rejected, resulting in ConnectionLostError. Patching the `_run_wkhtmltopdf` so no real rendering runs during the tour. runbot-243444 Forward-Port-Of: odoo/enterprise#123720
This fix adjusts internal tests so the timesheet assistant is set up only after its required test data handlers are ready. It helps prevent false test failures and supports more reliable delivery of timesheet-related updates.
Original PR description
Before this commit, the component was mounted in the `beforeEach` block before its `onRpc` mocks were registered. This caused the initial data fetch to fail because the mocks were not yet available during initialization. This commit fixes the test by moving the component mount (`doAction`) inside the test block, strictly after the mocks are defined. Forward-Port-Of: odoo/enterprise#123683
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
The planning app now shows the correct wording when a single resource lacks the required role for a shift. This avoids an unprofessional typo in a user-facing warning and makes the message clearer for planners.
Original PR description
Currently, when a (or multiple) resource(s) do not have the role for a particular shift, a warning is displayed. However, in the case where only one resource does not have the correct role, the following warning was displayed, "resource_name don't have the required role for this shift", instead of "doesn't". task-6153932
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
The timesheet assistant now shows the envelope icon again for existing email-based matching rules. This keeps older rules visually clear while preserving support for Gmail-related activities.
Original PR description
Issue: The email activity icon (fa-envelope) is not displayed for matched email rules. Cause: The email icon mapping was replaced with gmail_activity to support Gmail events. However, existing aw.rule records still use the email activity type, causing an icon key mismatch. Fix: Restore the email icon mapping while keeping the gmail_activity mapping so both activity types display the email icon. Task-6370391
The shop floor order list now places manufacturing orders with scheduled work ahead of unscheduled ones. This helps operators see planned work in the expected priority order and reduces confusion when managing work centers.
Original PR description
## Problem In shop floor, MOs with unplanned work orders get sorted before MOs that have planned operations, which contradicts the normal nulls last sorting for work orders. ## Solution We will…
## Problem In shop floor, MOs with unplanned work orders get sorted before MOs that have planned operations, which contradicts the normal nulls last sorting for work orders. ## Solution We will update the sorting logic in the MrpDisplay component to more gracefully handle falsy date_start values, sorting them to the end. ## Steps to reproduce (runbot 19) 1. Create 2 MOs with an operation (work order) involving a work center, we'll call them A and B. 2. Open Shop Floor and open the work center that the MOs' work orders belong to, and note they are ordered A, B (this is fine, neither are planned so the precedence falls back to id 3. Go back to MO B and plan it. This should give it precedence in Shop Floor 4. Under the work center in Shop Floor, note that the MOs are still ordered A, B, despite B's work order having a start date and A's work order not having one To further motivate this being unintended, you can go to Manufacturing > Operations > Work Orders, and you'll see MO B's work order sitting at the top of the list. opw-6303323 Forward-Port-Of: odoo/enterprise#121885 Forward-Port-Of: odoo/enterprise#121693
This fixes an automated Knowledge app test that was failing after a dropdown was changed to a select menu. It also makes the test more reliable by addressing timing issues, helping ensure future updates are validated consistently.
Original PR description
The dropdown for property definition type was replaced with a select menu, leading to an error in the tour as it tried to search for the previous implementation which contained a button. There are also changes to fix the race conditions that exist in the tour which were not evident due to the original issue Related pr: https://github.com/odoo/odoo/pull/234484 runbot-238409 Forward-Port-Of: odoo/enterprise#121958
Version: --------- - saas-18.4+ Steps to reproduce: ---------------------- 1. Install `stock` and `purchase` module 2. Create a storable and tracking product with a vendor. 3. Create a reordering rule: Route = Buy, Min Qty = 10, Max Qty = 20 and Trigger `manual` 4. Create a receipt for 10 units from the vendor and confirm it.(Mark as todo). 5. Observe the Order button is hidden in reorder rule(expected—incoming qty covers the minimum) 6. Delete the receipt move line. 7. Open reord
Original PR description
Version: --------- - saas-18.4+ Steps to reproduce: ---------------------- 1. Install `stock` and `purchase` module 2. Create a storable and tracking product with a vendor. 3. Create a reordering…
Version:
---------
- saas-18.4+
Steps to reproduce:
----------------------
1. Install `stock` and `purchase` module
2. Create a storable and tracking product with a vendor.
3. Create a reordering rule: Route = Buy, Min Qty = 10, Max Qty = 20
and Trigger `manual`
4. Create a receipt for 10 units from the vendor and confirm it.(Mark as todo).
5. Observe the Order button is hidden in reorder rule(expected—incoming qty covers the minimum)
6. Delete the receipt move line.
7. Open reordering rule and check order button
Issue:
------
After deleting a confirmed incoming move, the Order button on the reordering rule
does not reappear, even though there is no longer any incoming quantity to cover
the minimum threshold.
Cause:
-------
https://github.com/odoo/odoo/blob/adabd8cc47b1c5992f0f92631da73977be8beaca/addons/stock/views/stock_orderpoint_views.xml#L55-L56
The Order button visibility is driven by `qty_to_order > 0` on the orderpoint.
`qty_to_order` itself resolves to `qty_to_order_computed` (a stored field) when no
manual override is set:
https://github.com/odoo/odoo/blob/adabd8cc47b1c5992f0f92631da73977be8beaca/addons/stock/models/stock_orderpoint.py#L317-L319
```
qty_to_order─depends─>qty_to_order_computed (stored)
│
└─ reads qty_forecast (non-stored, computed)
│
└─ depends on product_id.stock_move_ids.
```
`_compute_qty_to_order_computed` checks whether `qty_forecast < product_min_qty`.
If so, it calculates how much to order to reach `product_max_qty`. When a confirmed
incoming move exists, its quantity is included in `qty_forecast`,
https://github.com/odoo/odoo/blob/adabd8cc47b1c5992f0f92631da73977be8beaca/addons/stock/models/stock_orderpoint.py#L347
This return False.
So, `qty_to_order_computed = 0` → button hidden.
To avoid recomputing `qty_to_order_computed` for all orderpoints on every stock
move change severe performance issue — see [Commit](https://github.com/odoo/odoo/commit/6f2d1b26b34129cfbd62d2fe44f306bfe89794b5
),
`qty_forecast` is intentionally excluded from
`@api.depends` on `qty_to_order_computed`. Instead,
`_update_orderpoints()` is called selectively from `create()` and `write()` to
schedule a targeted recompute via `env.add_to_compute()`.
However, `unlink()` never called `_update_orderpoints()`, so deleting a move left
`qty_to_order_computed` stale at 0 — the Order button stayed hidden permanently.
Solution:
---------
- `_update_orderpoints()` now returns the found orderpoints recordset.
- `unlink()` calls `_update_orderpoints()` before deletion to capture the affected
orderpoints (product_id / location data still accessible), then calls
`_compute_qty_to_order_computed()` immediately after `super().unlink()`.
opw-6174454
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#275119
Forward-Port-Of: odoo/odoo#264039**Steps to reproduce:** - Install Accounting and l10n_ar_withholding - Switch to an Argentinian company (e.g. (AR) Responsable Inscripto) - Create a 0% Payment Withholding tax: * Tax Type: Customer Payment Withholding * Amount: 0.00 % * Add an account for the tax distribution lines - Create an invoice with a tax - Confirm the invoice - Pay the invoice: * Withholdings: - Add a line with the created 0% Payment Withholding tax - Add a line with another Payment
Original PR description
**Steps to reproduce:** - Install Accounting and l10n_ar_withholding - Switch to an Argentinian company (e.g. (AR) Responsable Inscripto) - Create a 0% Payment Withholding tax: * Tax Type: Customer…
**Steps to reproduce:**
- Install Accounting and l10n_ar_withholding
- Switch to an Argentinian company (e.g. (AR) Responsable Inscripto)
- Create a 0% Payment Withholding tax:
* Tax Type: Customer Payment Withholding
* Amount: 0.00 %
* Add an account for the tax distribution lines
- Create an invoice with a tax
- Confirm the invoice
- Pay the invoice:
* Withholdings:
- Add a line with the created 0% Payment Withholding tax
- Add a line with another Payment Withholding tax
- Create Payment
- Go to the payment
**Issue 1:**
When clicking on the first withholding line, a JS error is raised due to a missing index (i.e. currency_id).
**Cause 1:**
One of the fields has an aggregate sum function applied on it (i.e. amount_currency).
As it is a monetary field, the corresponding currency field is required in the view.
**Issue 2:**
When resetting the payment to draft, the withholding line with the 0% tax is deleted.
As the withholding table is not editable, it is not possible to add the line again.
**Cause 2:**
When the payment is reset to draft, the state of the associated journal entry is also set to draft and a "_sync_dynamic_lines" is triggered, which remove tax lines having a zero amount during the process.
**Solution 2:**
Keep all the lines with a Customer Payment Withholding tax as it is not possible to add a withholding line in the payment afterwards.
opw-6298058
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#274604
Forward-Port-Of: odoo/odoo#271555Problem: When filtering lost leads and grouping them, the lost leads are not counted in the groups' totals. Steps to Reproduce: 1. Go to CRM 2. Go to Reporting > Leads 3. Select List View 4. Before applying any grouping, check the total number of leads and make sure there are some closed leads among the leads and that the applied filter includes the inactive/lost leads 5. Apply any grouping 6. Check how the sum of the groups totals doesn't equal the leads total Cause: When readin
Original PR description
Problem: When filtering lost leads and grouping them, the lost leads are not counted in the groups' totals. Steps to Reproduce: 1. Go to CRM 2. Go to Reporting > Leads 3. Select List View 4. Before…
Problem: When filtering lost leads and grouping them, the lost leads are not counted in the groups' totals. Steps to Reproduce: 1. Go to CRM 2. Go to Reporting > Leads 3. Select List View 4. Before applying any grouping, check the total number of leads and make sure there are some closed leads among the leads and that the applied filter includes the inactive/lost leads 5. Apply any grouping 6. Check how the sum of the groups totals doesn't equal the leads total Cause: When reading a group, the domain from the applied filter gets optimized, meaning that the applied rules get simplified logically. https://github.com/odoo/odoo/blob/f4d079cc5a9c47672cf1a6747bb073e8e74f7350/addons/web/models/models.py#L421 When looking for all leads, we filter by both active and inactive leads, but the optimize method removes both of them since active=TRUE OR active=FALSE = TRUE always. When removed, no filtering on the active field is in the domain now, which leads to the search method returning only active leads (default behaviour of search method when the active field is not set in the domain). opw-6302388 Forward-Port-Of: odoo/odoo#272390
Steps to reproduce: - Install `account` module - Enable dark mode - Open `view_account_form` to create a record - On the Accounting page, open type dropdown - The dropdown background remains in light mode This commit applies $dropdown-bg on `o_field_account_type_selection` as in odoo/odoo@0cd148eb389078c896aaa719af5733d05377fd1c Forward-Port-Of: odoo/odoo#274626 Forward-Port-Of: odoo/odoo#271352
Original PR description
Steps to reproduce: - Install `account` module - Enable dark mode - Open `view_account_form` to create a record - On the Accounting page, open type dropdown - The dropdown background remains in light mode This commit applies $dropdown-bg on `o_field_account_type_selection` as in odoo/odoo@0cd148eb389078c896aaa719af5733d05377fd1c Forward-Port-Of: odoo/odoo#274626 Forward-Port-Of: odoo/odoo#271352
When printing the sale details report from the POS ("Print Report"), no date or time appeared on the ticket. During the receipt refactor to shared backend templates, the sale details template and its frontend data builder stopped rendering the print date that previous versions displayed at the bottom of the report. This commit adds the current date and time to the sale details `extra_data` and renders it after the totals, restoring the previous behavior. opw-6348476 --- I confirm I
Original PR description
When printing the sale details report from the POS ("Print Report"), no date or time appeared on the ticket.
During the receipt refactor to shared backend templates, the sale details template and its frontend data builder stopped rendering the print date that previous versions displayed at the bottom of the report.
This commit adds the current date and time to the sale details `extra_data` and renders it after the totals, restoring the previous behavior.
opw-6348476
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#273734Problem: when creating a form using the website form builder for models with attributes of type "Reference", these fields also appear in the "Type" builder option for these form fields. The website form builder does not define the template for such fields because the template for such a field cannot be defined generically. Since the template is not defined for reference attributes, a traceback is thrown when a user attempts to add set those attributes as field type. This issue can be reprodu
Original PR description
Problem: when creating a form using the website form builder for models with attributes of type "Reference", these fields also appear in the "Type" builder option for these form fields. The website form builder does not define the template for such fields because the template for such a field cannot be defined generically. Since the template is not defined for reference attributes, a traceback is thrown when a user attempts to add set those attributes as field type. This issue can be reproduced using the following steps with the hr_recruitment addon installed. 1. Add a form on the website 2. Click on it 3. Change 'Form' > 'Action' to 'Apply for a job' 4. Add a field 5. Change its 'Type' to 'UTM reference' Solution: By blocking the model attributes with type "Reference" from being listed under the website form builder field "Type" list, the traceback error can be prevented. task-6317084 Forward-Port-Of: odoo/odoo#273412
Steps to reproduce ------------------- - Install sale_project, accountant and project_timesheet_forecast_sale modules; - Activate analytic accounting in the settings; - Add an outstanding account to the bank journal’s manual outgoing payment method; - Create a new billable project; - Open the top menu, add vendor bills and open it; - Create a new bill from there, it should use the project’s analytic distribution; - Confirm it and create a payment; - Open the payment’s journal entry, i
Original PR description
Steps to reproduce ------------------- - Install sale_project, accountant and project_timesheet_forecast_sale modules; - Activate analytic accounting in the settings; - Add an outstanding account to…
Steps to reproduce ------------------- - Install sale_project, accountant and project_timesheet_forecast_sale modules; - Activate analytic accounting in the settings; - Add an outstanding account to the bank journal’s manual outgoing payment method; - Create a new billable project; - Open the top menu, add vendor bills and open it; - Create a new bill from there, it should use the project’s analytic distribution; - Confirm it and create a payment; - Open the payment’s journal entry, it is using the analytic distribution too; Why is it happening -------------------- When opening a vendor bill from the project, the project_id is added to the account.move's context to use the correct analytic distribution when we create a bill. If we create a payment after accessing the bill from this route, the context is transfered to account.payment.register, and then to the payment's entry lines in the `_create_payments` method. Due to the `_compute_analytic_distribution` method, the project's distribution is used on the payment's entry. We propose to filter out payment lines in this compute method. opw-6329475 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275076
# How to reproduce - Create a new product - Add a reordering rule to that product with : - Trigger : Auto - Min : > Forecast - Activate dev mode - Go to Seetings > Technical > Automation > Scheduled Actions - Find the "Procurement: run Scheduler" action & run it manually # The issue We get a traceback : psycopg2.errors.SerializationFailure: could not serialize access due to concurrent update # Cause In Odoo, we use an isolation level of "REPEATABLE READ" for transactions : htt
Original PR description
# How to reproduce - Create a new product - Add a reordering rule to that product with : - Trigger : Auto - Min : > Forecast - Activate dev mode - Go to Seetings > Technical > Automation > Scheduled…
# How to reproduce - Create a new product - Add a reordering rule to that product with : - Trigger : Auto - Min : > Forecast - Activate dev mode - Go to Seetings > Technical > Automation > Scheduled Actions - Find the "Procurement: run Scheduler" action & run it manually # The issue We get a traceback : psycopg2.errors.SerializationFailure: could not serialize access due to concurrent update # Cause In Odoo, we use an isolation level of "REPEATABLE READ" for transactions : https://github.com/odoo/odoo/blob/7c35e183d6cc33a6e5d20e5e97ffef79e03b49d4/odoo/sql_db.py#L373 Even with that isolation level psql can throw a `SerializationFailure` if a transaction attempts to update a row that was modified by another transaction after the isolation snapshot was taken. ### Example that will raise an error : Session 1 ```SQL BEGIN ISOLATION LEVEL REPEATABLE READ; UPDATE accounts SET balance = balance - 100 WHERE id = 1; ``` Session 2 ```SQL BEGIN ISOLATION LEVEL REPEATABLE READ; UPDATE accounts SET balance = balance - 50 WHERE id = 1; COMMIT; ``` Back to Session 1 ```SQL COMMIT; ``` When running our action, we do this : https://github.com/odoo/odoo/blob/dff0835346f30fd1ef77260d94bcceeeab4d9051/addons/stock/models/stock_rule.py#L697-L703 Which correspond exactly to the first example : We first update some records with their compute Then `orderpoints.sudo()._procure_orderpoint_confirm(...)` creates a new transaction, update some rows & commits : https://github.com/odoo/odoo/blob/dff0835346f30fd1ef77260d94bcceeeab4d9051/addons/stock/models/stock_orderpoint.py#L716-L719 https://github.com/odoo/odoo/blob/dff0835346f30fd1ef77260d94bcceeeab4d9051/addons/stock/models/stock_orderpoint.py#L781-L783 Finally, we commit the original transaction with `_commit_progress(1)` # Proposed solution Inverse the order of `_commit_progress(1)` and `orderpoints.sudo()._procure_orderpoint_confirm(...)` so we commit the first transaction before starting the second one. opw-6261675 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#268616
When opening a table that has no order, `setTable` recycles an existing empty floating order instead of creating a new one (to avoid leaving dangling blank orders behind). The filter only checked for the absence of a table, lines and finalized state, so it could grab any empty floating order, including one deliberately created for takeout or delivery. Steps to reproduce: - Open a restaurant POS with presets enabled (e.g. Dine in / Takeaway). - Cashier A creates a new floating order for a ph
Original PR description
When opening a table that has no order, `setTable` recycles an existing empty floating order instead of creating a new one (to avoid leaving dangling blank orders behind). The filter only checked for…
When opening a table that has no order, `setTable` recycles an existing empty floating order instead of creating a new one (to avoid leaving dangling blank orders behind). The filter only checked for the absence of a table, lines and finalized state, so it could grab any empty floating order, including one deliberately created for takeout or delivery. Steps to reproduce: - Open a restaurant POS with presets enabled (e.g. Dine in / Takeaway). - Cashier A creates a new floating order for a phone customer: selects the Takeaway preset with a future time slot, but has not added any product yet. - Meanwhile, cashier B opens an empty table from the floor screen. - => The takeout order is assigned to the table and becomes a dine-in order, losing its takeout context. Only recycle blank direct sale orders: skip orders that have a floating order name, a scheduled preset time or a preset different from the config default, as those were created on purpose. Tapping a table while on a blank dine-in scratch order still converts it as before. opw-6041750 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262573
In this PR https://github.com/odoo/odoo/pull/237069 we used t-att-class for applying the style and because of that style was not properly applying and ICE was visible on address page on initial rendering for a moment even it does not have anything to do with MA. Used t-att-style instead t-att-class. task-5208254 Forward-Port-Of: odoo/odoo#274678
Original PR description
In this PR https://github.com/odoo/odoo/pull/237069 we used t-att-class for applying the style and because of that style was not properly applying and ICE was visible on address page on initial rendering for a moment even it does not have anything to do with MA. Used t-att-style instead t-att-class. task-5208254 Forward-Port-Of: odoo/odoo#274678
Description of the issue/feature this PR addresses: When grouping datetime fields by hour, `read_group` formats the group display label using `hh:00 dd MMM`. In Babel/LDML formatting, `hh` represents a 12-hour clock. Since the format does not include an AM/PM marker, afternoon/evening hours are displayed ambiguously in grouped views. Current behavior before PR: A datetime value in the afternoon is grouped under a 12-hour label without AM/PM. For example, records around `13:50` are dis
Original PR description
Description of the issue/feature this PR addresses: When grouping datetime fields by hour, `read_group` formats the group display label using `hh:00 dd MMM`. In Babel/LDML formatting, `hh` represents…
Description of the issue/feature this PR addresses:
When grouping datetime fields by hour, `read_group` formats the group display label using `hh:00 dd MMM`.
In Babel/LDML formatting, `hh` represents a 12-hour clock. Since the format does not include an AM/PM marker, afternoon/evening hours are displayed ambiguously in grouped views.
Current behavior before PR:
A datetime value in the afternoon is grouped under a 12-hour label without AM/PM.
For example, records around `13:50` are displayed under:
01:00 20 Mar
Similarly, a datetime value around `16:20` may be grouped under:
04:00 26 Mar
This is ambiguous because the group header does not indicate whether the hour is AM or PM.
Example screenshot showing records around 13:xx grouped under `01:00`:
<img width="310" height="240" alt="image" src="https://github.com/user-attachments/assets/8768f2e8-9aaa-436b-af9f-40055a6032e9" />
Desired behavior after PR is merged:
Hour-based datetime group labels should be unambiguous.
The hour grouping format now uses `HH:00 dd MMM`, so grouped datetime labels render using a 24-hour clock.
For example:
13:00 20 Mar
16:00 26 Mar
This fixes the datetime hour grouping label shown in grouped list views and other `read_group` consumers.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#275219
Forward-Port-Of: odoo/odoo#274724The test_cache test failed a couple times on a timeout error, this is because the more modules are installed, the longer it takes to index them all and generate the json document. [runbot-240550](https://runbot.odoo.com/odoo/error/240550) Forward-Port-Of: odoo/odoo#274773
Original PR description
The test_cache test failed a couple times on a timeout error, this is because the more modules are installed, the longer it takes to index them all and generate the json document. [runbot-240550](https://runbot.odoo.com/odoo/error/240550) Forward-Port-Of: odoo/odoo#274773
Steps to reproduce: - Create a promotion program (e.g. "10% discount on your order", reward_point_mode "per order") and restrict its rule to a specific product A; leave the minimum quantity at 0 - Open a PoS session and add any other product B to the order Issue: The discount was applied even though the order contained none of the rule's valid products. Cause: In `pointsForPrograms`, a rule was only gated on its quantity and amount thresholds (`totalProductQty < rule.minimum_qty`), nev
Original PR description
Steps to reproduce: - Create a promotion program (e.g. "10% discount on your order", reward_point_mode "per order") and restrict its rule to a specific product A; leave the minimum quantity at 0 -…
Steps to reproduce: - Create a promotion program (e.g. "10% discount on your order", reward_point_mode "per order") and restrict its rule to a specific product A; leave the minimum quantity at 0 - Open a PoS session and add any other product B to the order Issue: The discount was applied even though the order contained none of the rule's valid products. Cause: In `pointsForPrograms`, a rule was only gated on its quantity and amount thresholds (`totalProductQty < rule.minimum_qty`), never on the actual presence of a valid product in the order. Program templates (promotion, promo_code, next_order_coupons) create rules with minimum_qty = 0, so a product-restricted rule passed with zero matching items and, in "order" point mode, granted its points unconditionally. The same hole existed in `_canGenerateRewards` for scanned coupon programs, where rules act as conditions. The backend does not have this issue: `_program_check_compute_points` in sale_loyalty skips any rule whose valid products are not present in the order. Fix: Mirror the backend behavior in the PoS frontend: skip a product-restricted rule in `pointsForPrograms` when no (non-reward) order line matches its valid products, and make `_canGenerateRewards` return false in the same situation. Gift card and eWallet flows are unaffected since their "money"/"unit" point modes already gave 0 points when the trigger product was absent. opw-6357241 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275073
The native `warnings.deprecated` decorator strictly requires a string literal as its first positional argument and cannot be applied as a bare decorator. This commit enforces the same type verification in the fallback implementation for Python < 3.13. Follow-up of odoo/odoo@42fcc766af0584ef720a1cee5beb7878cdd1a572 runbot-941402 Forward-Port-Of: odoo/odoo#275037
Original PR description
The native `warnings.deprecated` decorator strictly requires a string literal as its first positional argument and cannot be applied as a bare decorator. This commit enforces the same type verification in the fallback implementation for Python < 3.13. Follow-up of odoo/odoo@42fcc766af0584ef720a1cee5beb7878cdd1a572 runbot-941402 Forward-Port-Of: odoo/odoo#275037
When uploading a font file "FontName 123 Light.otf" the baseFontName needs to be quoted in the font-face CSS to be valid. Single font files parsing for the shortestNamedFont now also correctly keeps the weight for the targetFonts. Description of the issue/feature this PR addresses: Uploaded fonts with spaces in the name are not working. Current behavior before PR: When uploading a font with a space in the filename like "FontName 123 Light.otf" the css declaration in the attachement i
Original PR description
When uploading a font file "FontName 123 Light.otf" the baseFontName needs to be quoted in the font-face CSS to be valid. Single font files parsing for the shortestNamedFont now also correctly keeps…
When uploading a font file "FontName 123 Light.otf" the baseFontName needs to be quoted in the font-face CSS to be valid.
Single font files parsing for the shortestNamedFont now also correctly keeps the weight for the targetFonts.
Description of the issue/feature this PR addresses:
Uploaded fonts with spaces in the name are not working.
Current behavior before PR:
When uploading a font with a space in the filename like "FontName 123 Light.otf" the css declaration in the attachement is wrong and not working:
```css
@font-face {
font-family: FontName 123 Light;
font-style: normal;
font-weight: 400;
src: url("/web/content/1057/FontName 123 Light.otf");
}@font-face {
font-family: FontName 123 Light;
font-style: normal;
font-weight: 400;
src: url("/web/content/1057/FontName 123 Light.otf");
}
```
Desired behavior after PR is merged:
The font name is now correctly quoted and the font attributes are no longer overwritten for the shortestNameFont:
```css
@font-face {
font-family: "FontName 123 Light";
font-style: normal;
font-weight: 400;
src: url("/web/content/1057/FontName 123 Light.otf");
}@font-face {
font-family: "FontName 123 Light";
font-style: normal;
font-weight: 300;
src: url("/web/content/1057/FontName 123 Light.otf");
}
```
Info @wt-io-it
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#273534
Forward-Port-Of: odoo/odoo#268842Use case -------- A recurring sale order, is automatically invoiced. The transaction is postprocessed and crash with this traceback ``` File "/home/odoo/src/enterprise/saas-19.2/sale_subscription/models/sale_order.py", line 1881, in _handle_automatic_invoices invoice._post() File "/home/odoo/src/custom/private/openerp_enterprise/models/subscription_assignation.py", line 439, in _post posted_moves = super()._post(soft=soft) ^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/odoo/src/custom/private
Original PR description
Use case -------- A recurring sale order, is automatically invoiced. The transaction is postprocessed and crash with this traceback ``` File…
Use case
--------
A recurring sale order, is automatically invoiced. The transaction is postprocessed and crash with this traceback
```
File "/home/odoo/src/enterprise/saas-19.2/sale_subscription/models/sale_order.py", line 1881, in _handle_automatic_invoices
invoice._post()
File "/home/odoo/src/custom/private/openerp_enterprise/models/subscription_assignation.py", line 439, in _post
posted_moves = super()._post(soft=soft)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/custom/private/openerp_enterprise/models/account.py", line 193, in _post
posted = super()._post(soft)
^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/enterprise/saas-19.2/hr_payroll_expense/models/account_move.py", line 21, in _post
res = super()._post(soft=soft) # Posting will automatically reconcile same-account-same-matching lines
^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/enterprise/saas-19.2/l10n_in_reports/models/account_move.py", line 135, in _post
to_post = super()._post(soft=soft)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/enterprise/saas-19.2/account_loans/models/account_move.py", line 20, in _post
posted = super()._post(soft)
^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/enterprise/saas-19.2/sale_subscription/models/account_move.py", line 21, in _post
posted_moves = super()._post(soft=soft)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/enterprise/saas-19.2/account_invoice_extract/models/account_invoice.py", line 235, in _post
posted = super()._post(soft)
^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/enterprise/saas-19.2/account_asset/models/account_move.py", line 130, in _post
posted = super()._post(soft)
^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/saas-19.2/addons/l10n_it_edi/models/account_move.py", line 360, in _post
return super()._post(soft)
^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/saas-19.2/addons/l10n_in_edi/models/account_move.py", line 156, in _post
res = super()._post(soft=soft)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/saas-19.2/addons/account_peppol_response/models/account_move.py", line 42, in _post
res = super()._post(soft)
^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/saas-19.2/addons/sale/models/account_move.py", line 149, in _post
invoice.js_assign_outstanding_line(line.id)
File "/home/odoo/src/enterprise/saas-19.2/account_accountant/models/account_move.py", line 589, in js_assign_outstanding_line
super().js_assign_outstanding_line(line_id)
File "/home/odoo/src/odoo/saas-19.2/addons/account/models/account_move.py", line 6430, in js_assign_outstanding_line
return lines.reconcile()
^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/saas-19.2/addons/account/models/account_move_line.py", line 3324, in reconcile
return self._reconcile_plan([self])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/saas-19.2/addons/account/models/account_move_line.py", line 2978, in _reconcile_plan
plan_list, all_amls = self._optimize_reconciliation_plan(reconciliation_plan)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/odoo/src/odoo/saas-19.2/addons/account/models/account_move_line.py", line 2940, in _optimize_reconciliation_plan
amls._check_amls_exigibility_for_reconciliation(shadowed_aml_values=shadowed_aml_values)
File "/home/odoo/src/odoo/saas-19.2/addons/account/models/account_move_line.py", line 2832, in _check_amls_exigibility_for_reconciliation
raise UserError(_("You can not reconcile cancelled entries."))
You can not reconcile cancelled entries.
```
Because an old transaction: state = 'reconciled' but is_reconciled is false get attached to the new invoice. The the tx.payment_id.move_id was cancelled by the accounting team, and the invoice was reconcilled directly with the bank statement.
So we end up with a cancelled move that block any further invoice for this subscription.
Solution
--------
According to accounting team, the move_id of the payment is always posted except if there is some manual intervention. We make sure we link only transaction with payment with posted moved
opw-6368231
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#274764Currently the number grouping for Portuguese and Hindi is missing. Number grouping is used to separate long numbers in logical groups to make then easier to read. In Western countries, the grouping is usually done in groups of three digits (e.g. `1,000,000` instead of `1000000`), while in India, the grouping is done in groups of two digits after the first three digits (e.g. `10,00,000` instead of `1000000`). Source: https://www.unicode.org/cldr/charts/48/by_type/numbers.number_formatting_patt
Original PR description
Currently the number grouping for Portuguese and Hindi is missing. Number grouping is used to separate long numbers in logical groups to make then easier to read. In Western countries, the grouping is usually done in groups of three digits (e.g. `1,000,000` instead of `1000000`), while in India, the grouping is done in groups of two digits after the first three digits (e.g. `10,00,000` instead of `1000000`). Source: https://www.unicode.org/cldr/charts/48/by_type/numbers.number_formatting_patterns.html#24a93b3d14ba17b2 All languages will be revised in a follow-up `master` PR. [task-6320391](https://www.odoo.com/odoo/project.task/6320391) Forward-Port-Of: odoo/odoo#275237 Forward-Port-Of: odoo/odoo#274443
#### Issue: When a credit note is renamed so that it sorts before the related invoices, the lot assigned on invoice previews can become incorrect. Already posted invoices can appear to consume the first lot again. Example: A sale order is delivered in 2 batches: 10 units from SN01, then 10 units from SN02. Invoice 1 correctly shows SN01 and Invoice 2 correctly shows SN02. If Invoice 1 is refunded, re-invoiced, and the credit note is then renamed so it sorts before the invoices, Invoice
Original PR description
#### Issue: When a credit note is renamed so that it sorts before the related invoices, the lot assigned on invoice previews can become incorrect. Already posted invoices can appear to consume the…
#### Issue: When a credit note is renamed so that it sorts before the related invoices, the lot assigned on invoice previews can become incorrect. Already posted invoices can appear to consume the first lot again. Example: A sale order is delivered in 2 batches: 10 units from SN01, then 10 units from SN02. Invoice 1 correctly shows SN01 and Invoice 2 correctly shows SN02. If Invoice 1 is refunded, re-invoiced, and the credit note is then renamed so it sorts before the invoices, Invoice 2 can incorrectly switch back to SN01. #### Steps to reproduce: - Enable "Display Lots & Serial Numbers on Invoices". - Create a sale order for 20 units of a tracked product. - Deliver 10 units from the first lot/serial number and 10 units from a second one in a backorder. - Create and post 2 invoices, one for each delivery. - Create and post a credit note for the first invoice. - Create and post a new invoice for 10 units. - Reset the credit note to draft, rename it so that it sorts before the invoices, then repost it. - Check the lot previews on the invoices. #### Root Cause: _get_invoiced_lot_values() orders invoice lines with move_name, which is mutable, then computes the previously invoiced quantities from that order. When a refund is renamed so it sorts before the invoices, the set of "previous" invoice lines changes. On top of that, reversed invoices are filtered out too broadly, even when their reversing move should not yet impact the current invoice chronology. #### Fix: Order invoice lines with immutable move ids instead of move_name, and only ignore reversed invoices once their reversing move is also before the current invoice in the effective chronology. This keeps posted invoices stable while preserving the re-invoice behavior. opw-6110232 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#264776
When an orderpoint fails during a portal user's transaction (e.g., eCommerce checkout), the system catches the `Procurement Exception` and logs a warning activity on the product template. The exception handler uses `.sudo().activity_schedule()`, which bypasses the write access restriction but leaves `env.uid` as the portal user. Therefore, the restricted portal user permanently becomes the `create_uid` (Author) of the activity. System exception activities should always be authored by the s
Original PR description
When an orderpoint fails during a portal user's transaction (e.g., eCommerce checkout), the system catches the `Procurement Exception` and logs a warning activity on the product template. The…
When an orderpoint fails during a portal user's transaction (e.g., eCommerce checkout), the system catches the `Procurement Exception` and logs a warning activity on the product template. The exception handler uses `.sudo().activity_schedule()`, which bypasses the write access restriction but leaves `env.uid` as the portal user. Therefore, the restricted portal user permanently becomes the `create_uid` (Author) of the activity. System exception activities should always be authored by the system (OdooBot), never by a portal or public user. This context leak corrupts the activity metadata by injecting an external user ID into internal backend logs. Chain `.with_user(SUPERUSER_ID)` to the `.sudo()` call in `stock_orderpoint.py` when scheduling the exception activity. This ensures the environment context is stable and the activity is authored by OdooBot, which transcends multi-company record rules. Steps to Reproduce on Runbot/Fresh Database on version 17.0: 1. Enable Multi-Company with Company A and Company B. Set Company B as the active company for the website. 2. Restrict the main Admin (Runbot) user strictly to Company A. 3. Create a Shared Product (Company field left blank). 4. Set a Reordering Rule (Orderpoint) for the product that is guaranteed to fail routing. 5. Navigate to the frontend website and sign up as a new user (this creates a Portal User in Company B). 6. As the newly signed-up Portal User, complete an eCommerce checkout for the shared product. 7. The checkout succeeds, but the backend triggers the orderpoint failure and logs the exception activity on the product template. 8. Check the chatter for this product: the `create_uid` is incorrectly set to the Portal User instead of OdooBot (1). 9. (In 19.0 Upgrade) Log in as the Admin user (set strictly to view Company A), navigate to the product, and the AccessError for reading will appear due to this leaked id. [opw-6253978](https://www.odoo.com/odoo/my-support-tasks/6253978?debug=assets) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#275140 Forward-Port-Of: odoo/odoo#269395
The translate button next to a translatable field saves the record before opening the translation dialog for its id. Since https://github.com/odoo/odoo/commit/a85ca9679e3855936afc66b034d05d75f672dd26 it saves record.model.root rather than the record itself. When the field belongs to a new record still edited inside an x2many, for example an answer added in the survey question popup, saving the root only saves the parent and the new line keeps no database id. The dialog then opens with the id set
Original PR description
The translate button next to a translatable field saves the record before opening the translation dialog for its id. Since https://github.com/odoo/odoo/commit/a85ca9679e3855936afc66b034d05d75f672dd26…
The translate button next to a translatable field saves the record before opening the translation dialog for its id. Since https://github.com/odoo/odoo/commit/a85ca9679e3855936afc66b034d05d75f672dd26 it saves record.model.root rather than the record itself. When the field belongs to a new record still edited inside an x2many, for example an answer added in the survey question popup, saving the root only saves the parent and the new line keeps no database id. The dialog then opens with the id set to false and calls update_field_translations on it, which builds WHERE id = false and the database rejects it with operator does not exist: integer = boolean. Such a record gets no id of its own, and after a save and reload there is no reliable way to match the saved line back to the one that was clicked, so the dialog can never open for it. A canTranslate getter in TranslationButton returns false for a new record whose model root is another record, which is exactly a line still edited inside an x2many, and the template only renders the button when it is true. The variant in editable lists, where model.root is a list rather than a record, was handled in https://github.com/odoo/odoo/commit/cb34b318004c3ca9db755d8dbbad429609220df3. Steps to reproduce: 1. Activate a second language in Settings > Translations > Languages 2. Open the Surveys app and create a survey 3. Add a question, then in the Answers tab add a line and type a value 4. Click the EN button next to the answer, fill the second language, and Save => RPC error operator does not exist: integer = boolean from WHERE id = false Ticket [link](https://www.odoo.com/odoo/project.task/6260427) opw-6260427 Forward-Port-Of: odoo/odoo#270635 Forward-Port-Of: odoo/odoo#267781
`ImDispatch.subscribe()` lazily starts the dispatcher thread with: ```py if not self.is_alive(): self.start() ``` However, this check isn't atomic: two subscribers can reach it at the same instant (a bunch of clients reconnecting after a downtime/restart/etc..) and two of them can have the condition "is not alive" and both of them will call `start()`. Technically, this is not a big deal, since `Thread.start()` will only successfully starts once and raise an Error `Threads c
Original PR description
`ImDispatch.subscribe()` lazily starts the dispatcher thread with: ```py if not self.is_alive(): self.start() ``` However, this check isn't atomic: two subscribers can reach it at the same instant (a…
`ImDispatch.subscribe()` lazily starts the dispatcher thread with:
```py
if not self.is_alive():
self.start()
```
However, this check isn't atomic: two subscribers can reach it at the same instant (a bunch of clients reconnecting after a downtime/restart/etc..) and two of them can have the condition "is not alive" and both of them will call `start()`.
Technically, this is not a big deal, since `Thread.start()` will only successfully starts once and raise an Error `Threads can only be start3e once` which is already catch and ignored with `contextlib.suppress(RuntimeError)`.
But this is a problem with some APM (like sentry) where they override `threading.Thread.start` to do something different than stdlib, and so something we can not know nor control.
The RuntimeError guard only tells us who's allowed to actually spawn the thread. It says nothing about code attached to `start()`/`run()` that runs on every attempt, win or lose, and that's exactly the part we don't control.
For example, sentry-sdk (before 2.34) patches `Thread.start` to wrap `self.run` on *every* call, not only the one that actually starts the thread:
```py
def sentry_start(self, *a, **kw):
self.run = wrap(self.run) # <- side effect, runs unconditionally
return real_start(self, *a, **kw)
```
Under the race described above, every losing call still wraps `self.run` before failing. Each wrapper forwards its own extra argument to the one it wraps, without dropping what it already received, so each layer adds one more positional argument. By the time the thread actually starts, `ImDispatch.run()` ends up called with N positional arguments instead of one:
```
TypeError: ImDispatch.run() takes 1 positional argument but N were given
```
N varies from one report to the next simply because it depends on how many subscribers happened to race on that particular restart.
Rather than relying on the RuntimeError to paper over a race we still allow to happen, we remove the race itself: wrapping the check and the `start()` call in a lock guarantees at most one caller ever gets past the "not alive" check. `start()` is called exactly once, so there's nothing left for third-party instrumentation to react to more than once.
Note:
Reproduced locally by firing many concurrent `subscribe()` calls at a freshly created `ImDispatch` with sentry-sdk 1.39.2 installed: the TypeError appears reliably, with the reported argument count matching the number of racing calls. The same scenario no longer fails once the lock is in place, regardless of the sentry-sdk version installed.
sentry-3928947199Steps to reproduce: - Open Helpdesk app on smartphone - Go to a ticket - the star priority_field is black with a gray background => bug task-6369589 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Original PR description
Steps to reproduce: - Open Helpdesk app on smartphone - Go to a ticket - the star priority_field is black with a gray background => bug task-6369589 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Description of the issue/feature this PR addresses: Currently, in the website_sale_stock module, there is no backend validation when subscribing to notifications for products without stock. This allows public users to potentially use emails that belong to registered accounts. Current behavior before PR: Users could subscribe to stock notifications for products that don’t exist or cannot be added (no stock). Public users could use emails already associated with registered accounts, allowi
Original PR description
Description of the issue/feature this PR addresses: Currently, in the website_sale_stock module, there is no backend validation when subscribing to notifications for products without stock. This…
Description of the issue/feature this PR addresses: Currently, in the website_sale_stock module, there is no backend validation when subscribing to notifications for products without stock. This allows public users to potentially use emails that belong to registered accounts. Current behavior before PR: Users could subscribe to stock notifications for products that don’t exist or cannot be added (no stock). Public users could use emails already associated with registered accounts, allowing them to subscribe on behalf of another user. No validation is enforced, leading to potential security issues. Desired behavior after PR is merged: Adding a subscription for a non-existent or unavailable product raises a ValidationError. Public users trying to subscribe with an email that belongs to a registered user receive an AccessError prompting them to sign in first. Backend validation prevents misuse of registered user emails and improves security. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274937 Forward-Port-Of: odoo/odoo#271880
Problem: When creating a product from an invoice form view, the list price set on the product is not saved on the product template. After creating the product, when checking the product from the products list, the set list price is not shown. Steps to reproduce: 1. Go to Accounting > Customers > Invoices 2. Create a new invoice 3. Create and edit a new product from the invoice line and set a new list price for the new product 4. Go to Sales > Products and open the created product 5. Che
Original PR description
Problem: When creating a product from an invoice form view, the list price set on the product is not saved on the product template. After creating the product, when checking the product from the…
Problem: When creating a product from an invoice form view, the list price set on the product is not saved on the product template. After creating the product, when checking the product from the products list, the set list price is not shown. Steps to reproduce: 1. Go to Accounting > Customers > Invoices 2. Create a new invoice 3. Create and edit a new product from the invoice line and set a new list price for the new product 4. Go to Sales > Products and open the created product 5. Check the list price of the product 6. Notice how the set list price is not shown on the product form view Cause: Product variants show lst_price while product templates show list_price on their form views. When creating a product from the invoice line, the shown form is for the product variant. When setting the list price on the product variant form (lst_price in that case), the inverse method of llst_price, which sets the list_price in return, is called during the creation of the variant, after the template has been created and saved. As a result, editing the list price does not trigger a write on the already saved product template, causing the list_price of the variant to be different than the list_price of the template. opw-6272825 Forward-Port-Of: odoo/odoo#270614
Since [1] elements within the link preview can be focused. However, when pressing tab an error is raised. This commit prevents this error from happening. [1]: https://github.com/odoo/odoo/commit/34db19f4a2b42d7e41205d7d793f5b3f408c19af task-6366337 Forward-Port-Of: odoo/odoo#275336 Forward-Port-Of: odoo/odoo#274682
Original PR description
Since [1] elements within the link preview can be focused. However, when pressing tab an error is raised. This commit prevents this error from happening. [1]: https://github.com/odoo/odoo/commit/34db19f4a2b42d7e41205d7d793f5b3f408c19af task-6366337 Forward-Port-Of: odoo/odoo#275336 Forward-Port-Of: odoo/odoo#274682
In previous fix https://github.com/odoo/odoo/commit/29b24a17a40d0f45a0e459cda68ca53b7d40075e we called _force_update_l10n_fr_f10_moves when the value of _compute_l10n_fr_pdp_flow_10_start_date changed as if it was stored, whitch it's not, calling the method each time the compute was triggered. Now _force_update_l10n_fr_f10_moves is run when l10n_fr_pdp_annuaire_start_date is set. Forward-Port-Of: odoo/odoo#275019
Original PR description
In previous fix https://github.com/odoo/odoo/commit/29b24a17a40d0f45a0e459cda68ca53b7d40075e we called _force_update_l10n_fr_f10_moves when the value of _compute_l10n_fr_pdp_flow_10_start_date changed as if it was stored, whitch it's not, calling the method each time the compute was triggered. Now _force_update_l10n_fr_f10_moves is run when l10n_fr_pdp_annuaire_start_date is set. Forward-Port-Of: odoo/odoo#275019
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
This update corrects a warning message appearing when editing a partner view in Odoo. The warning incorrectly indicated a missing 'true' field, despite the field being intentionally hidden. This change ensures a smoother user experience by removing the misleading warning.
Original PR description
There is a warning saying that there is no "true" field when editing the view. But in reality this is currently working as expected and the field is hidden. related to opw-5947987 Forward-Port-Of: odoo/odoo#275218 Forward-Port-Of: odoo/odoo#273041
Miscellaneous changes
Before this commit, calls to the route `/shop?search=<search_term>` would lead the search for `product_public_categories` to use a query in the shape of `product_id in (<list_of_ids>)`. In the case where the cardinality of the product table becomes large (> 10k products), if `search_term` is very broad-spectrum, the length of `list_of_ids` reaches the size of the product table. In that case the query generated to search for categories becomes significantly slow to parse (> 14 seconds in our te
Original PR description
Before this commit, calls to the route `/shop?search=<search_term>` would lead the search for `product_public_categories` to use a query in the shape of `product_id in (<list_of_ids>)`. In the case…
Before this commit, calls to the route `/shop?search=<search_term>` would lead the search for `product_public_categories` to use a query in the shape of `product_id in (<list_of_ids>)`. In the case where the cardinality of the product table becomes large (> 10k products), if `search_term` is very broad-spectrum, the length of `list_of_ids` reaches the size of the product table. In that case the query generated to search for categories becomes significantly slow to parse (> 14 seconds in our tests). This commit proposes as an alternative to resort to a sub-query to fetch the product ids that are relevant in the context of `product_public_categories`. Because of how the list of products is acquired initially, we can't rely on the `_search()` method to generate the sub-query. The following table shows average gains for "increasing search term specificity". Here, "specificity" is determined by the amount of characters in the search term and the related number of hits expected from the search. ### Cardinality ~250k records | Metric | ~228,872 hits | ~2,870 hits | ~377 hits | ~11 hits | | :--- | :--- | :--- | :--- | :--- | | Before Fix | 14.027s | 5.726s | 3.183s | 3.139s | | After Fix | 1.216s | 3.794s* | 1.330s | 1.301s | ### Cardinality 10k records | Metric | 8,897 hits | 1,122 hits | 15 hits | 0 hits | | :--- | :--- | :--- | :--- | :--- | | Before Fix | 1.386s | 3.232s* | 0.580s | 0.395s | | After Fix | 0.756s | 3.410s* | 0.772s | 0.572s | *Note: The increase in response time in the second column is caused by a different execution path taken (fuzzy search) which becomes the most significant path in terms of execution time once the other queries are optimized. opw-6299343 Forward-Port-Of: odoo/odoo#271306