Thursday, August 20, 2026
13 changes · saas-19.1
Resolved issues and error corrections
French branch companies can now activate PDP electronic invoicing without hitting a save error. The fix ensures the system correctly uses the parent company's accounting setup when configuring a branch, preventing interruptions during rollout.
Original PR description
**Steps to reproduce:** * Create a **French** parent company and a branch. * Activate **Electronic Invoicing (PDP)** for the parent company. * Switch to the branch while keeping both the **parent…
**Steps to reproduce:**
* Create a **French** parent company and a branch.
* Activate **Electronic Invoicing (PDP)** for the parent company.
* Switch to the branch while keeping both the **parent company** and the **branch** selected in the company switcher.
* Go to **Settings → French Localization → Activate Electronic Invoicing**.
* Activate **Electronic Invoicing (PDP)** for the branch.
* Select the **Participate in the pilot phase** checkbox and try to save settings.
**Observed behavior:**
* A traceback occurs with the error: `psycopg2.errors.SyntaxError: syntax error at or near ")"` on `IN ()` in the SQL query inside `_force_update_l10n_fr_f10_moves`.
**Cause:**
* `_force_update_l10n_fr_f10_moves` searches for receivable/payable accounts using `company_ids IN companies.ids`.
* A branch company has no accounts assigned directly to it — accounts belong to the parent company — so the search returns an empty list.
* Passing an empty tuple to `IN %(account_ids)s` generates `IN ()`, which is invalid PostgreSQL syntax.
**Fix:**
* Replace `('company_ids', 'in', companies.ids)` with
`('company_ids', 'parent_of', companies.ids)` in the account search
inside `_force_update_l10n_fr_f10_moves`.
* This ensures that accounts owned by a parent company are correctly
found when the given companies are branches, since branch companies
inherit their parent's chart of accounts.
opw-6394650
Forward-Port-Of: odoo/odoo#282849
Forward-Port-Of: odoo/odoo#277232This fix keeps the mobile time picker open while users enter a time, preventing the form behind it from unexpectedly taking focus. It improves reliability when scheduling items in Planning on phones and tablets.
Original PR description
Steps to reproduce ================== - Use a mobile viewport - Go to planning - Click on an empty cell - Click on the date - On the bottomsheet, click on the time at the bottom - Try to type 12:34 => Only 1 is entered and then the start_datetime field is focused behind the bottom sheet Cause of the issue ================== The <input type="time"/> listen to the onchange event. We listen to rawPickerProps changes using a reactive call. shouldFocus is then set to true, and the focus is done after the next render. The onchange event is called at a different time depending on the platform. On IOS and Firefox desktop: after changing hours or minutes On Android: once the apply button is clicked On Chrome desktop: After entering a single char Solution ======== The bottomsheet is only displayed when env.isSmall && hasTouch(). It doesn't make sense to focus the input, since we don't handle the keyboard in that case. opw-6386252
Pricing rules created from a product variant now remain linked to that exact variant instead of being applied to the broader product template. This prevents unintended pricing changes across multiple variants and helps businesses keep variant-level prices accurate.
Original PR description
Issue: --- When you apply pricing on product variant form, pricing is instead applied on product template. Steps to reproduce: 1- Open a product variant. 2- From prices tab, add a pricelist rule. Save the variant. 3- Re-open pricelist rule. As you see, the variant is not set. Cause & Fix: --- This is because `applied_on` is changed to `1_product` when `display_applied_on` is set to `1_product`. However, `display_applied_on` is also set to `1_product` when item is created from variant. We can check that case using `default_product_id`. opw-6421193 Forward-Port-Of: odoo/odoo#280303
Accounting users can now export German Datev ATCH zip files even when an invoice's main attachment was added through a log note. This prevents an access error that blocked non-admin users from completing the export.
Original PR description
### Issue: When an invoice has an image as its main attachment added via a log note, any non-admin user who did not create the attachment gets an `AccessError` when exporting the Datev ATCH zip ###…
### Issue: When an invoice has an image as its main attachment added via a log note, any non-admin user who did not create the attachment gets an `AccessError` when exporting the Datev ATCH zip ### Cause: Since commit `e7c93e5a6f`, attachments uploaded via certain flows can be "orphaned" — their `res_model` is set to `False` and `res_id` to `0` via `_fix_attachments_on_record_from_files_data` This allows the attachment to appear in the chatter without being linked to the move's attachment list However, `_message_set_main_attachment_id` can still set such an orphaned attachment as `message_main_attachment_id` When a user without system rights tries to read it, the ORM access check uses `res_model=False` and `res_id=0`, which does not match the move the user has access to, raising an `AccessError` ### Steps to reproduce: - Install `l10n_de_reports` and switch to the DE company - Create and confirm an Invoice (any lines, any customer) - Add a Log Note with an image - Set Demo user's Accounting rights to `Invoicing & Banks` - Log in as Demo - Open the General Ledger - In the cog menu, choose `Datev ATCH (zip)` Before the fix, an `AccessError` is raised opw-6397804 Forward-Port-Of: odoo/enterprise#127787
Odoo now records the right VoIP call outcome when a call is answered or rejected in another softphone while Odoo is open. This prevents calls from being incorrectly marked as missed, improving call history accuracy for users who use external VoIP tools alongside Odoo.
Original PR description
Steps to reproduce: - Have an external VoIP software configured (e.g. Linphone) - Have your Odoo configured and opened too - Call your VoIP number, using your smartphone => Both the softphone and…
Steps to reproduce: - Have an external VoIP software configured (e.g. Linphone) - Have your Odoo configured and opened too - Call your VoIP number, using your smartphone => Both the softphone and Linphone ring - Answer or reject using Linphone => The VoIP call record in Odoo immediately switches from "Trying to call" to "Missed". While there was no guarantee for our VoIP integration to work alongside Linphone in 19.0, we decided this should be an easy safe enough fix. Starting 19.2 (with [1]), the fix will be simplified and hopefully prettier thanks to the ameliorations that were made. After this fix, provided Odoo is open while Linphone is used, the call records will now switch to the right terminated / rejected status, still immediately once Linphone answers / rejects. In future versions and especially 20.0+, the system will be different and will allow way more features like this one to work better (e.g. here the call record only even exists if Odoo is opened while using Linphone and we won't have any information about the call duration). [1]: https://github.com/odoo/enterprise/commit/942f32316ab02d8c739fe7fdd5ec2bdde472a68e task-6449259 Forward-Port-Of: odoo/enterprise#127077
This fix prevents errors when generating electronic product codes for inventory barcode records that include both tracked and untracked items. Tracked items now keep the correct tracking numbers, while untracked items receive a clear message instead of causing the process to fail.
Original PR description
Problem: `_compute_electronic_product_code` built `tracking_number_list` by filtering out move lines without a lot_id/lot_name, but kept iterating over the full, unfiltered `move_line_ids`. As soon…
Problem: `_compute_electronic_product_code` built `tracking_number_list` by filtering out move lines without a lot_id/lot_name, but kept iterating over the full, unfiltered `move_line_ids`. As soon as a tracked product had an untracked move line mixed in with tracked ones (e.g. a manufacturing byproduct move line with no lot), the two lists fell out of sync: at best tracking numbers got assigned to the wrong move line, at worst `tracking_number_list[i]` went out of range and raised an IndexError. Solution: Exclude untracked move lines from `move_line_ids` before building `tracking_number_list`, so both stay the same length and index- aligned. Untracked lines get their own explicit "no tracking number" error instead of breaking the alignment for the rest. Steps to reproduce: Open runbot V19 -> go to moves history (Inventory) -> add `electronic_product_code` to list view using studio -> remove filter/select all records -> https://anotepad.com/notes/jwxyskc2 Forward-Port-Of: odoo/enterprise#123859
DHL return label creation no longer fails when a sales order includes Incoterms. The fix sends the expected Incoterm code in the DHL request, preventing tracebacks during delivery confirmation.
Original PR description
Issue ----- When "return" is enabled, users get a traceback if the SO has incoterms. Steps to reproduce ----- - Set up DHL - enable return labels - Create a SO with incoterms & confirm it - Confirm the delivery > Traceback Cause ----- The request sent for the return label contains the incoterm record instead of its' code like in `dhl_rest_send_shipping` https://github.com/odoo/enterprise/blob/f6c94d4ca3ef4211a5ab00bf0b39f6a7675c8f79/delivery_dhl_rest/models/delivery_dhl.py#L371-L372 Which is not JSON serializable ----- Ticket: opw-6430371 Forward-Port-Of: odoo/enterprise#126459
Fixes an error that could block users from resetting a bank statement line back to draft in Accounting. This restores the expected workflow for correcting or revising bank transactions without encountering a server error.
Original PR description
Currently, an error occurs when resetting a **bank** statement line to draft. **Steps to Reproduce:** - Install the `Accounting` module. - Go to `Accounting Dashboard` and click the `three-dot` on…
Currently, an error occurs when resetting a **bank** statement line to draft. **Steps to Reproduce:** - Install the `Accounting` module. - Go to `Accounting Dashboard` and click the `three-dot` on bank journal. - Open `Transactions`. - Create a new `statement line`. - Select the `statement line`, click the `gear action`, and click `Reset to Draft`. `AttributeError: 'bool' object has no attribute 'setdefault'` After the [recent commit], when resetting the statement line to draft, the server action run [1] and the linked move is going reset to draft, and the method returns the result [2]. After the mentioned commit, the method returns True [3]. When the result from [4] is passed to clean_action, it raises an error [5]. This commit ensures that it returns None after resetting the statement line linked to the invoice to draft, as it previously returned None and same as like [6]. [recent commit]: https://github.com/odoo/odoo/commit/712718d9df0fd5044ac57fdd9ec58e64bece36c0 [1]- https://github.com/odoo/enterprise/blob/7ca28a1c079d22b60e3756ca9b4f404771f214e8/account_accountant/views/bank_rec_widget_views.xml#L541-L551 [2]- https://github.com/odoo/enterprise/blob/eae51e3ca155ca29e1de54f4bd223e7540b2aa7f/account_accountant/models/account_bank_statement.py#L112-L114 [3]: https://github.com/odoo/odoo/blob/b3444e4bd421a30229b0dc7c8d5eb6c78b8b51ed/addons/account/models/account_move.py#L6236-L6251 [4]: https://github.com/odoo/odoo/blob/a6f99706c6a62fc65666a0ff5e58fa465b41a6fb/addons/web/controllers/action.py#L53-L59 [5]: https://github.com/odoo/odoo/blob/b3444e4bd421a30229b0dc7c8d5eb6c78b8b51ed/addons/web/controllers/utils.py#L24 [6]: https://github.com/odoo/odoo/blob/d7df2e8acff9eb7066993fa6a0b0c6d7c85baabc/addons/account/models/account_payment.py#L1206-L1208 sentry-7354160052 Forward-Port-Of: odoo/enterprise#127189
When users try to archive an accounting journal that still contains draft entries, the warning now directs them to the correct Journal Entries list where those drafts can be found and handled. The journal form button is also renamed to better reflect that it opens journal items, reducing confusion and helping users resolve the issue without dead ends.
Original PR description
> Replaces https://github.com/odoo/odoo/pull/282286, which GitHub closed automatically after a bad force-push on my side: the branch was pushed from a shallow clone and its head lost its parent…
> Replaces https://github.com/odoo/odoo/pull/282286, which GitHub closed automatically after a bad force-push on my side: the branch was pushed from a shallow clone and its head lost its parent commit, leaving no common ancestor with 18.0. A PR in that state cannot be reopened, so this one continues from a clean branch with the exact same change. The review discussion is in that PR, and the rename asked for there is included here. ### Steps to reproduce 1. Go to `Accounting > Customers > Invoices` and create an invoice on a given journal, leaving it in draft. For the clearest case, leave it with no invoice line. 2. Go to `Accounting > Configuration > Journals`, open that journal and archive it. 3. `_check_auto_post_draft_entries` raises: *"You can not archive a journal containing draft journal entries. To proceed: 1/ click on the top-right button 'Journal Entries' from this journal form 2/ then filter on 'Draft' entries 3/ select them all and post or delete them through the action menu"*. 4. Follow those steps: click the `Journal Entries` smart button on the journal form. ### Current behaviour The list comes up empty, so the user concludes the error message is wrong, while the draft entries do exist. The instructions cannot be followed: - The smart button opens `action_account_moves_all_a`, which is named **"Journal Items"** and targets **`account.move.line`**, not `account.move`. The label of the button and the name of the action it opens do not match. - That action defaults to `search_default_posted: 1`, so no draft record is listed. - Draft entries with **no line at all** — commonly created through the incoming mail alias of a journal — have no `account.move.line`, so they stay invisible in that view even after switching the filter. - The action menu of a move line list offers no way to post or delete the entries, and the action sets `create: 0`. - The filter is labelled **"Unposted"**, not "Draft". The offending entries are only reachable through `Accounting > Accounting > Journal Entries`, filtering by journal and by "Unposted". ### Expected behaviour The error should point to a view where the records blocking the archiving are actually listed and actionable. ### This PR Two changes, the validation itself is unchanged: - The error message now points to `Accounting > Accounting > Journal Entries` and uses the real filter name, "Unposted". - The smart button of the journal form is renamed to **"Journal Items"**, so its label matches the action it opens and no longer suggests it lists journal entries. This was asked for in the review of the previous PR. Targeted at 18.0 because that is where the misleading message is being hit in practice; it is identical on 19.0 and master. If a translatable string change does not qualify for the stable series, tell me and I will retarget to master. Forward-Port-Of: odoo/odoo#282956
Electronic invoices sent through Peppol now use the reference from the actual invoice contact when one is set, rather than incorrectly using the parent company reference. This helps ensure customers receive invoice XML with the correct buyer identifier and reduces Peppol processing or reconciliation issues.
Original PR description
**Steps to reproduce:**
* Set up a French company and configure Peppol E-invoicing.
* Install `account_edi_ubl_cii` module.
* Create a company partner (customer) and set a **Reference** value on the company contact under
**Customer** -> **Settings** -> **Sales and Purchase**.
* Create a child contact under that company and set a different Reference value.
* Create an invoice using the child contact as the invoice partner and confirm the invoice.
* Send it via Peppol.
**Observed Behaviour:**
* The BuyerReference in the generated XML contains the reference of the parent
(commercial partner) Instead of the child contact used on the invoice.
**Cause:**
* The buyer reference was taken from the commercial partner instead of the
invoice partner.
**Fix:**
* Update the condition to use the invoice partner's reference when available;
Otherwise, fall back on the commercial partner's reference.
opw - 6330649
Forward-Port-Of: odoo/odoo#273700French customers with a valid SIREN or SIRET number are now correctly recognized as businesses even if no VAT number is recorded. This keeps the French e-Invoicing option available for eligible invoices and avoids unnecessary manual workarounds.
Original PR description
**Steps to reproduce:** - Install module `l10n_fr_pdp` and configure French e-Invoicing. - Create a customer has a valid SIREN/SIRET (company_registry) but no VAT number. - Create an invoice for the customer and confirm the invoice. - Check the available sending methods. **Observed Behavior:** The French E-Invoicing option is disabled because the customer is identified as a B2C partner when no VAT number is set. **Cause**: The B2C detection relies on the partner's VAT number instead of its SIREN/SIRET. As a result, French companies without a VAT number but with a valid SIREN are classified as B2C. **Fix**: Determine whether a partner is B2C based on the presence of a valid SIREN/SIRET (derived from `company_registry`) instead of the VAT number. This correctly identifies French business partners that are eligible for French e-Invoicing even when they do not have a VAT number configured. opw-6357756 Forward-Port-Of: odoo/odoo#278060
This fixes an issue where creating a new analytic distribution model during a bulk edit would close the dialog before users could finish entering details. Users can now complete and save the new model without losing their work, improving reliability for accounting workflows.
Original PR description
When mass-editing the Analytic Distribution field on several records at once, and creating a new distribution at once, will close the creation dialog before the user could fill it in. Steps to reproduce: - Enable Analytic Accounting - Open Accounting > Journal Items - Enable the Analytic Distribution column - Select 2 journal items and click on the Analytic Distribution - Click on 'Update', fill a distribution, then click "New Model" - Confirm the multi-edit update Issue: The create Analytic Distribution model dialog closes on its own instead of staying open, so the model can never be saved. Analysis: After https://github.com/odoo/odoo/commit/12a61fa5ab7c56a42020c50c683df8ed52f1fb01, in multi-edit, save() ends reloading the list, unmounting the AnalyticDistribution widget, that closes the model dialog it just opened. opw-6405219 Forward-Port-Of: odoo/odoo#281141
WhatsApp template messages with many mixed variable types now place each value in the correct placeholder. This prevents customers from receiving messages with incorrect or mismatched information.
Original PR description
**Issue**:
Sending a WhatsApp template with 10 or more variables can assign values to the wrong placeholders when the body contains mixed variable types, such as free text, field, or user name variables.
Templates containing only free-text variables are not affected.
**Reason**:
Meta consumes template parameters positionally, but for mixed variable types, Odoo built the parameter list using the template variable recordset order.
That order can differ from the numeric placeholder order, notably placing {{10}}, {{11}}, {{12}}... before {{1}}
when sending the message, as the payload parameters are not ordered by their numeric placeholder index.
**Fix:**
Sort body variables by their numeric placeholder index before preparing the Meta payload.
Task-6401501
Forward-Port-Of: odoo/enterprise#125671