Tuesday, September 1, 2026
12 changes · 19.0
Resolved issues and error corrections
Users who can view but not edit a sales order can now register invoice payments without hitting an access error. The system still logs the payment note on the order, while preserving restrictions that prevent those users from changing sales order details.
Original PR description
Description of the issue/feature this PR addresses: Registering a payment for a confirmed sale order must not require write access on the order. Today the automatic "Invoice %s paid" chatter…
Description of the issue/feature this PR addresses:
Registering a payment for a confirmed sale order must not require write access on the order. Today the automatic "Invoice %s paid" chatter notification is posted through message_post, which checks the caller's write permission via the model's _mail_post_access attribute [[1](https://github.com/odoo/odoo/blob/620c1e6510cee407b9962823a622b8405f7420ea/addons/mail/models/models.py#L66-L83)]. A user with read but not write access on the order (e.g. through fine-grained record rules) therefore gets an AccessError while registering the payment, even though the payment is actually registered.
sale.order is the only affected model that never defines _mail_post_access, while account.move [[2](https://github.com/odoo/odoo/blob/620c1e6510cee407b9962823a622b8405f7420ea/addons/account/models/account_move.py#L78)], hr.employee [[4](https://github.com/odoo/odoo/blob/620c1e6510cee407b9962823a622b8405f7420ea/addons/hr/models/hr_employee.py#L41)], hr.leave, project.task [[5](https://github.com/odoo/odoo/blob/620c1e6510cee407b9962823a622b8405f7420ea/addons/project/models/project_task.py#L102)], discuss.channel and several website models all allow posting chatter with read access only. Reported upstream in odoo/odoo#54081 (2020, closed "Need information", never fixed).
Current behavior before PR:
Registering a payment on an invoice linked to a read-but-not-writable sale order raises an AccessError. It is a side effect of _invoice_paid_hook() calling order.message_post(body=_("Invoice %s paid", name)) without sudo: message creation re-checks access on the linked document, and sale.order's missing _mail_post_access falls back to the mail.thread default 'write'. The error surfaces as "Message / create" on mail.message, masking the real cause.
Desired behavior after PR is merged:
Define _mail_post_access = 'read' on SaleOrder. The paid-invoice audit message is then logged with read access only, and registering the payment succeeds. Read-only users still cannot modify sale order fields — they can only add chatter messages and followers, the same trade-off Odoo already accepts for every other affected model. The change is minimal (one attribute) and appropriate for a stable series: no data model, method signature or XML changes.
Tests:
Added test_invoice_payment_on_read_only_sale_order to addons/sale/tests/test_access_rights.py. It blocks write access on the sale order via a record rule with perm_write, then asserts has_access('read') is True and has_access('write') is False, registers a payment as the restricted user without raising AccessError, and checks the "Invoice ... paid" message is present in the order's chatter.
Related:
- Closed odoo/odoo#54081.
- The _mail_post_access attribute was introduced by commit [[3](https://github.com/odoo/odoo/commit/e81708ba35046f272f6a48c7d88edbd59fbf0f8c)]; the read-access pattern is already used by account.move [[2](https://github.com/odoo/odoo/blob/620c1e6510cee407b9962823a622b8405f7420ea/addons/account/models/account_move.py#L78)], hr.employee [[4](https://github.com/odoo/odoo/blob/620c1e6510cee407b9962823a622b8405f7420ea/addons/hr/models/hr_employee.py#L41)] and project.task [[5](https://github.com/odoo/odoo/blob/620c1e6510cee407b9962823a622b8405f7420ea/addons/project/models/project_task.py#L102)].
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prThis fix stops Odoo live chat embeds from blocking common browser keyboard shortcuts when no Odoo shortcut hints are available. Users on websites with embedded live chat can keep using shortcuts like focusing the address bar, while Odoo shortcut overlays still work where they exist.
Original PR description
Description of the issue/feature this PR addresses: When `im_livechat` (or any page) boots the OWL web stack with no `[data-hotkey]` / `withOverlay` targets, pressing Alt still called…
Description of the issue/feature this PR addresses: When `im_livechat` (or any page) boots the OWL web stack with no `[data-hotkey]` / `withOverlay` targets, pressing Alt still called `preventDefault()` in `hotkey_service`. That blocked browser shortcuts such as Alt+D (focus address bar) on websites that embed the livechat scripts. See https://github.com/odoo/odoo/issues/267928 Current behavior before PR: - Pressing the overlay modifier (Alt, or Ctrl on macOS mapped to `"alt"`) always set `overlaysVisible = true` and called `preventDefault()`, even when there were no hotkeys to overlay. - A follow-up key (e.g. D while Alt is held) then also hit `preventDefault()` because overlays were considered visible. - Loading `/im_livechat/loader/...` + `assets_embed.js` on an external site therefore broke browser Alt shortcuts. Desired behavior after PR is merged: - `addHotkeyOverlays` returns whether overlays were actually displayed. - `preventDefault` on the overlay modifier runs only when there is at least one overlay target. - Pages with no hotkeys (typical livechat embed) leave browser shortcuts alone. - When hotkeys exist, Alt still shows overlays and cancels the default, same as before. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Closing an AI live chat conversation no longer triggers an unexpected chat window to appear. This improves the website visitor experience by making the chat close action behave as expected and avoiding confusing follow-up messages.
Original PR description
Closing the chat with the ai agent on the ai_livechat snippet results in a chatwindow popping up which gives a bad user experience. Steps to reproduce: - Log in as Mitchell Admin. - Go to website. -…
Closing the chat with the ai agent on the ai_livechat snippet results in a chatwindow popping up which gives a bad user experience. Steps to reproduce: - Log in as Mitchell Admin. - Go to website. - Click on edit and choose `Contact & Forms`. - Add the AI Livechat website snippet. - From the snippet options, add an AI Agent and choose a livechat team. Make sure that Mitchell Admin is configured as an operator for that livechat team (livechat channel). - Click on save. - Open an incognito tab. Log in as Marc Demo. - Go to Website. - Type a message inside the `ASK AI` text area and press enter. - Wait until you receive a response and then click close. - A chat window will popup with the messages of the conversation with the AI along with a message saying `Visitor has left the channel`. This happens because `close` button will call `closeConversation` => `livechatService.leave()` => `visitor_leave_session` => `_close_livechat_session` that posts a message that the visitor has left the channel. This commit solves the issue by setting the user who left the channel as the author of the `visitor left chat` message instead of OdooBot.
This change corrects how HR contract salary and payroll version information is updated in the employee HR context. It helps prevent incorrect version data from being saved, reducing the risk of payroll or contract salary inconsistencies for Belgian HR processes.
Original PR description
task-6521357
Users can now correct sales order line descriptions while an order remains open, even after the line has been delivered or invoiced. This keeps product changes protected on processed lines while removing confusing behavior where editability depended on the visible columns.
Original PR description
Descriptions on order lines become impossible to change after the line is delivered or invoiced, even though the order is still open. Interestingly, hiding the product column makes the description editable again. This shows that editing descriptions is already technically allowed, but currently depends on the column layout, which is confusing for users. Keep descriptions editable until the order is locked or cancelled. This lets users correct text without allowing changes to products on processed lines. Desired behavior after PR is merged: After a sale order is confirmed, users can modify descriptions while the order remains unlocked, regardless of the column layout. Products on processed lines remain protected. @moduon MT-15454 opw-6432243 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fixes Polish electronic invoice reporting so certain 0% EU reverse charge taxes are identified correctly in KSeF XML. Businesses using Polish EDI invoices will now send the expected reverse charge indicator and taxable base, reducing reporting errors and compliance risk.
Original PR description
**PROBLEM** K_12 taxes needs to be reported as reverse charge tax. **STEP TO REPRODUCE** 1. Create an invoice with the tax 0% EU U. 2. Send the invoice the ksef. 3. Open the xml, an notice P_18 value is 2 (meaning no reverse charge), and there is no tag P_13_10. expected behavior: P_18 = 1, P_13_10 = base for the tax. opw-6460338 Forward-Port-Of: odoo/odoo#281934
Sales of kit products now correctly exclude deliveries completed after the selected accrual entry date when calculating quantities delivered by that date. This prevents orders from incorrectly remaining eligible for invoicing when the delivery happened outside the reporting period.
Original PR description
When selling a kit, the qty_delivered_at_date was not ignoring moves that were done after the accrual_entry_date. Steps to reproduce: ------------------- * Create a kit with any component and make it's invoice policy "Delivered quantities" * Create a sale order for this kit and confirm it, change the order date to any date in the past * Validate the picking * Go check the "Invoiced to be issued" * Change the accrual_entry_date to a date before the picking was validated > Observation: The order still appears opw-6290222
Bank reconciliation now shows the matched bill or invoice number even when currency exchange differences are involved. This helps accounting users verify reconciliations more easily and avoids confusion when matching foreign-currency payments.
Original PR description
### Issue before this commit: In the bank reconciliation widget, the matched bill or invoice name is missing from the UI when a currency exchange difference occurs (e.g., when the payment date…
### Issue before this commit: In the bank reconciliation widget, the matched bill or invoice name is missing from the UI when a currency exchange difference occurs (e.g., when the payment date differs from the bill's exchange rate date). ### Steps to reproduce the issue: 1. Download Accounting and hr_expense_stripe 2. Go to currencies > euro > activate it and create a new rate (ex. 1.3 USD) with a previous date (ex. yesterday) 3. Go to Vendor Bills and create a new bill with: 1. Bill date posterior to the currency rate creted 2. EUR as currency 4. Go to Dashboard > Stripe Issuing 5. Crete a new bank matching with date previous than the date of the exchange rate created and the amount of the bill just created with minus sign 6. Reconcile it selecting the corresponding bill 7. The number of the reconciliated bill is not displayed ### Cause of the issue: The field count_reconciled_lines_excluding_exchange_diff on account.move.line was incorrectly defined as a fields.Boolean instead of fields.Integer. As a result, the Python backend casts the line count to a boolean (true) before sending it to the frontend. The JavaScript widget performs a strict equality check (=== 1) on this value. Since true === 1 evaluates to false, the UI fails to fetch the correct move data and hides the origin bill's name. ### Reason to introduce the fix: Changing the field type to fields.Integer is not stable so it has been decided to change the js file that was using it. opw-6425896
Fixes an issue where Argentine online stores could show a lower tax-excluded price on the product page than on the shop listing when a discounted pricelist was used. Customers now see consistent pricing across the catalog and product detail pages, reducing confusion during shopping.
Original PR description
Steps to produce: --- - Create a company with `Argentina` as the country. - Switch to the newly created company. - Create a new website for the `Argentina company`. - Create a pricelist with a `23%`…
Steps to produce: --- - Create a company with `Argentina` as the country. - Switch to the newly created company. - Create a new website for the `Argentina company`. - Create a pricelist with a `23%` discount on the sales price for all products. - Create a new product, set the sale price to 100, remove all tax, and publish. - Go to the website and switch to the newly created Argentina company website. - Go to the Shop page and open the product. Issue: --- - The tax-excluded price (`Precio s/Imp. Nac.`) displayed on the shop catalog card differs from the tax-excluded price displayed on the product detail page. Root cause: --- - In `_get_additionnal_combination_info`, [1] returns the unit price with the pricelist discount already applied. However, when `combination_info['has_discounted_price']` [2] is `True`, the method applies the discount again manually, resulting in the pricelist discount being applied twice on the product detail page. Solution: --- - Remove the redundant discount calculation block. This ensures that the tax-excluded price displayed on the product detail page matches the price shown on the shop catalog card. [1]https://github.com/odoo/odoo/blob/7f9560bd0ff66882459593a2d043c0197ceec0bb/addons/l10n_ar_website_sale/models/product_template.py#L61-L62 [2]https://github.com/odoo/odoo/blob/7f9560bd0ff66882459593a2d043c0197ceec0bb/addons/l10n_ar_website_sale/models/product_template.py#L71-L74 opw-6480531 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283761
Accountants without company access-rights permissions can now generate BOE files for Spanish Modelo 115 tax reports without an access error. The change prevents the export wizard from unnecessarily trying to update company data, keeping the process aligned with normal accounting permissions.
Original PR description
Users who only have accounting rights (not the Settings > Users Companies > Access Rights group) get an access error on the Companies model when generating the BOE file for the Modelo 115 tax…
Users who only have accounting rights (not the Settings > Users Companies > Access Rights group) get an access error on the Companies model when generating the BOE file for the Modelo 115 tax reports, even though exporting a BOE file has nothing to do with editing company configuration and should be available to any accountant. Steps to reproduce: ------------------- * Log in as a user with accounting rights only (not part of the Companies > Access Rights group) * Go to Accounting > Reporting > Tax Return, open the Mod 115 report * Click the gear icon > BOE > Generate BOE > Observation: An AccessError is raised: "You are not allowed to modify 'Companies' (res.company) ... This operation is allowed for the following groups: Access Rights", even though the user is not trying to edit the company. Why the fix: ------------ The BOE wizard shared by Mod 111/115/303 declares a `company_partner_id` field, related to `company_id.partner_id`, with `readonly=False`. That field is invisible in every view and only exists to compute the domain of `partner_bank_id`; it was never meant to be edited by the user. Because it is declared writable, the ORM attaches an inverse to the related field, so saving the wizard (which happens when generating the BOE, since the field, though invisible, is still part of the view and thus of the saved values) writes `company.partner_id` back onto `res.company`, even though the value never actually changes. That implicit write requires write access on res.company, which is only granted to the Access Rights group, causing the error for regular accountants. Dropping `readonly=False` keeps the field as a plain readonly related field, still usable for the bank account domain, without ever triggering that spurious write. opw-6388869 Forward-Port-Of: odoo/enterprise#129841 Forward-Port-Of: odoo/enterprise#126661
This fix keeps expected quantities aligned between reordering rules and the forecast report when manufactured products move between warehouses. It prevents misleading negative forecasts that could cause businesses to reorder items unnecessarily or make poor stock planning decisions.
Original PR description
Currently, users encounter discrepancies between the reordering rule and forecast quantities when products are in inter-warehouse transit. ## Steps to produce: - Install Manufacturing and Sales -…
Currently, users encounter discrepancies between the reordering rule and forecast quantities when products are in inter-warehouse transit.
## Steps to produce:
- Install Manufacturing and Sales
- Enable Multi-Step Routes and MTO from settings.
- Create a warehouse with 3 steps manufacturing and Short Name: WH2
- Go to warehouse 1 and Enable `Resupply From: My Company - warehouse # 2`
- Routes > Open the resupply route > click WH2/Stock -> Inter-warehouse transit
- Set supply method to 'Take From Stock, if unavailable, Trigger Another Rule' and save.
- Create a tracked product 'Generic Chair' with both MTO and warehouse resupply route enabled.
- Create an empty Manufacturing BoM for the `Generic Chair`
- Create a manual reordering rule for chair with
- location: WH2/Stock
- Min:5 and Max: 10
- Create and confirm a sales order for chair with quantity 1.
- Open the related manufacturing change the quantity to 5 and confirm it.
- Open the forecast report for chair in warehouse 2 the forecasted quantity is 4
- Open the reordering rule and observe the forecasted quantity.
## Observed behavior:
The forecast report for the chair in the reordering rule shows -1, even though 5 units are expected from the manufacturing order. This is inconsistent with the forecast report and could cause errors when reordering the generic item.
## Root cause:
When the user changes the quantity in a Manufacturing Order (MO), the write method is called with values such as:
`[[2, 9], [0, 'virtual_14', {...}]]`
As a result, the existing `move_finished_ids` records are unlinked and recreated using only the field values that are present in the MO form view.
Since the Final Location field in `move_finished_ids` is not present in the MO form view, its value is not included when `move_finished_ids` is recreated.
Consequently, the create method of the stock.move model applies the default value at [1] and sets the final destination location to:
`WH2/Stock → Post Production`
This changes the `location_final_id` of the finished move to Post Production.
When the user opens the Forecast Report for the warehouse, `_get_report_data` searches for incoming and outgoing quantities across all child locations of the warehouse at [2]. Since Post Production is included in the warehouse's child locations, its quantities are correctly included in the forecast report.
However, reordering rules work differently. They calculate quantities only for the specific location configured on the orderpoint, which in this case is WH2/Stock
At [3], because `location_final_id` of `move_finished_ids` is set to Post Production, and Post Production is not a child location of WH2/Stock, the incoming quantity from this move is not included in the reordering rule calculation.
As a result, the forecasted quantity is calculated as -1 (outgoing) instead of 4, which leads to the reported issue.
[1]-
https://github.com/odoo/odoo/blob/5e84fdd99e34836a15cadc4fdf4b6bc449727e58/addons/mrp/models/stock_move.py#L278-L279
[2]-
https://github.com/odoo/odoo/blob/5e84fdd99e34836a15cadc4fdf4b6bc449727e58/addons/stock/report/stock_forecasted.py#L156-L168
[3]-
https://github.com/odoo/odoo/blob/c4de5361fb207916175332dcf6815c0814ecf09c/addons/stock/models/product.py#L437-L441
## Solution:
Keep the final location ID set during the initial quantity change if it already exists on the manufacturing order, since the order will ultimately end up in WH2/Stock as its final location in the chain. This ensures consistent forecast quantities between the reordering rule and the forecast report, while also keeping the final location consistent across the manufacturing order and its finished stock moves.
opw-6432985This fix prevents a Helpdesk ticket list from crashing when users open it after navigating through an email alias. It ensures the system uses the correct Helpdesk Team information, so support teams can access tickets normally from the team page.
Original PR description
### Steps to Reproduce: 1. In Debug mode, go to Aliases 2. Click on any active Alias, ex. customer-care 3. Click on "Open Parent Document" smart button 4. Click on "Tickets" smart button and observe…
### Steps to Reproduce: 1. In Debug mode, go to Aliases 2. Click on any active Alias, ex. customer-care 3. Click on "Open Parent Document" smart button 4. Click on "Tickets" smart button and observe error ### Description of the issue/feature this PR addresses: **Issue:** When navigating from an email alias to its parent document (e.g., a Helpdesk Team), the web client incorrectly retains the `active_id` and `active_model` of the alias in the context. **Solution:** We updated the `action_view_ticket` method in `helpdesk.team` to explicitly inject the correct `active_model` and `active_id` into the context before calling `_for_xml_id`. This overwrites the polluted Alias data before the window action is evaluated. ### Current behavior before PR: Clicking the "Tickets" smart button passes the old alias context into the action. This bad data flows into the ticket view, which attempts to look up a Helpdesk Team using the Alias's ID to generate the empty list help message, resulting in a `MissingError`. ### Desired behavior after PR: The Python action sanitizes the context at the source, ensuring that the XML action and subsequent view evaluations receive the correct Helpdesk Team ID. Ultimately, the view will load normally without crashing. opw-6395638 Forward-Port-Of: odoo/enterprise#129669 Forward-Port-Of: odoo/enterprise#125232