Friday, September 18, 2026
34 changes · saas-19.2
Enhancements to existing features
The Canary Islands chart of accounts now includes the proper receivable and payable accounts for IGIC taxes. This allows Odoo to post IGIC tax adjustments to the right accounts during tax period closing and reporting, improving accounting accuracy for affected Spanish localizations.
Original PR description
… CoA The Canary Islands chart of accounts was missing dedicated receivable/payable accounts for IGIC. Without these, Odoo cannot automatically post tax adjustments to the correct accounts when closing tax periods or generating the tax report. Add accounts 470700 (Hacienda Pública, deudor por IGIC, asset_receivable) and 475700 (Hacienda Pública, acreedora por IGIC, liability_payable) to the common Canary Islands account template, and set them as tax_receivable_account_id and tax_payable_account_id on all IGIC tax groups. Change to the canaries association their correspondent account codes overwriting the names. task-6225928 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
Inventory availability searches now run much faster by using existing stock quantity records instead of scanning broader stock movement data. This improves responsiveness for businesses with large product catalogs or many warehouse operations, especially when filtering products by available stock.
Original PR description
**Problem:** Searching on free_qty can be slow when there are many stock.move and stock.quant. The search method uses _compute_quantities_dict() to compute the free_qty based on stock.move and…
**Problem:** Searching on free_qty can be slow when there are many stock.move and stock.quant. The search method uses _compute_quantities_dict() to compute the free_qty based on stock.move and stock.quant, which is expensive. **Solution:** A similar field, qty_available, has a faster search method based on stock.quant only. This method can be adapted to support fast searching on free_qty by also aggregating the reserved_qty and subtracting it from the qty_available. **Perf Table:** Record: product.template, with ~20k stock.picking and most products w/o moves. |Record count|Time before|Queries before|Time after|Queries after| |------------|-----------|--------------|----------|-------------| |10k |2.14s |214 |370ms |45 | |50k |6.06s |644 |829ms |50 | |100k |11.42s |1196 |1.05s |46 | opw-6266096 Forward-Port-Of: odoo/odoo#287363 Forward-Port-Of: odoo/odoo#270434
The Spanish reports app now includes the required return type setup for Mod 420 tax returns. This helps ensure the report can be handled consistently with other tax returns, supporting smoother filing workflows.
Original PR description
Add the `es_mod420_tax_return_type` record to `account_return_data.xml` to support the Mod 420 tax return, including its association with the `l10n_es.mod_420` report. This change is done so that 420 can have return types, which bedore it didn't. task-6225928
Resolved issues and error corrections
The product feed now correctly excludes video thumbnails from extra product images sent to Google Merchant Center. This also avoids loading large image files unnecessarily, reducing the risk of feed generation failures on catalogs with many images.
Original PR description
Description of the issue/feature this PR addresses: The Google Merchant Center feed builds the extra image URL list of each product, and must skip the `product.image` records holding a video, as…
Description of the issue/feature this PR addresses:
The Google Merchant Center feed builds the extra image URL list of each product, and must skip the `product.image` records holding a video, as their image is only a thumbnail of that video. It filters those out by accessing `image_128`, which is wrong on two counts:
- A video record does have an `image_128`: the thumbnail, fetched from the video URL or uploaded by the user. Video thumbnails were therefore listed in the feed as if they were product images.
- Binary fields are read and base64-encoded in full by default, so the binary content of every extra product image was loaded into memory just to evaluate a truthiness check. On a database with ~4261 products with images, rendering the feed exhausts the worker memory limit and raises an out-of-memory error.
Current behavior before PR:
`_get_extra_image_1920_urls()` keeps every extra image whose `image_128` is set, including video thumbnails, and forces the ORM to fetch and base64-encode the full content of every extra image attachment.
<img width="2038" height="1462" alt="image" src="https://github.com/user-attachments/assets/e3b375e5-ac17-4b5c-b0c3-59264d7e36f7"/>
Desired behavior after PR is merged:
The records are filtered on `video_url`, the field that actually flags a video, so videos are properly excluded and no image binary is read at all.
opw-6513194
Forward-Port-Of: odoo/odoo#286782Fixes a cart update issue that could make the rental date picker appear but stop responding after using quick reorder. Customers can now continue selecting rental dates normally, reducing checkout friction for rental purchases.
Original PR description
`updateCartSummary` refreshes `o_wsale_shorter_cart_summary` via `replaceWith`, detaching the node and inserting a new one. `reorderProduct` in quick_reorder.js ends up restarting an interaction on the previous node instead of the new one. For rental products, this leaves the daterange picker rendered but inert after a quick reorder from the cart. This commit updates the existing node instead of replacing it, so its identity is preserved. Issue present since PR: https://github.com/odoo/odoo/pull/234965
This fixes an issue in Safari where replacing selected text at the start of an editable note could delete the selection without inserting the typed character. Users editing notes or other rich text content in Safari should now see typed text replace selections reliably.
Original PR description
When using Safari, if the first character of the editable is selected and a character is pressed, the selection content is removed, but the character is not inserted. It seems that Safari does not trigger the actual `input` event, nor its native behavior, if the initial anchor node is detached from the DOM after `beforeinput`. This commit avoids this issue by preventing Safari from proceeding with the insertion right after the deletion by instead re-triggering the `insertText` command. Steps to reproduce: - Use Safari - Go to a To do note - Select the first word - Press a letter => The first word was deleted but the letter was not inserted. task-6445669 Forward-Port-Of: odoo/odoo#288848 Forward-Port-Of: odoo/odoo#281223
Odoo now blocks the creation of API keys that are already expired, helping users avoid mistakes when copying example settings from documentation. This reduces confusion and ensures newly created keys can actually be used as intended.
Original PR description
Prevent creating API keys that are already expired. One typical case is when you copy/paste the documentation and end up creating keys that are already expired, without noticing. Forward-Port-Of: odoo/odoo#286677 Forward-Port-Of: odoo/odoo#286548
The calendar view now updates properly when the browser window changes from desktop to mobile size. This prevents the desktop sidebar from staying open on smaller screens, giving users a cleaner mobile experience.
Original PR description
See commits Forward-Port-Of: odoo/odoo#288954 Forward-Port-Of: odoo/odoo#288329
Generic demo leave types no longer include a specific country, so they will not interfere when setting a company's country in demo or development databases. This keeps country validation active for real leave data while avoiding unnecessary setup blockers caused by sample data.
Original PR description
_check_country_change_holidays constraint blocks writes to res.company.country_id whenever hr.leave/hr.leave.allocation records exist whose leave type country differs from the new company country. Unset country_id on the generic holiday_status_* demo leave types they are not meant to represent a specific country's holiday policy, so they should not carry a country at all. With country_id set to False, they no longer participate in the country-change constraint. The constraint keeps protecting real country changes on business data, while no longer blocking legitimate demo installs where we configure the main company with our country but rely on demo data for dev instances. Related to https://github.com/odoo/odoo/pull/277346 Forward-Port-Of: odoo/odoo#278749
Fixed an issue where opening Point of Sale orders for a company could show a blank screen if one of its delivery addresses had no name. The order list now uses the company name as a fallback, so staff can view relevant orders without disruption.
Original PR description
Steps to reproduce: - Create a company contact with a delivery address that has no name - Make a PoS order for the delivery address and pay it - Open the PoS, open the customer list, and click…
Steps to reproduce: - Create a company contact with a delivery address that has no name - Make a PoS order for the delivery address and pay it - Open the PoS, open the customer list, and click "Orders" on the company Issue: The screen goes blank. Cause: The ticket screen is opened with the company name as search term. The server domain searches on `partner_id.complete_name`, so the orders of the address contact are returned too. They are then fuzzy matched on `getPartnerName()`, which returns `false` for a partner without a name, and `fuzzyLookup` calls a string method on it. The error is raised during rendering, so the whole app is destroyed. Fix: Make `getPartnerName()` always return a string, and fall back on the parent name, like the complete name does. This way the orders of the address contact are still listed when searching on the company name, instead of being filtered out by an empty name. opw-6578541 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#288880
The spreadsheet component has been updated to the latest version, bringing fixes for pivot table totals and demo spreadsheet behavior. This improves the accuracy of spreadsheet-based reporting, especially when pivot dimensions are hidden or collapsed.
Original PR description
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/3e0951a53b [REL] 19.2.30 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0)…
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/3e0951a53b [REL] 19.2.30 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0) https://github.com/odoo/o-spreadsheet/commit/d499bd8bcd [IMP] demo: debounce xml template build [Task: 6574005](https://www.odoo.com/odoo/2328/tasks/6574005) https://github.com/odoo/o-spreadsheet/commit/acf1b01cd8 [FIX] demo: fix scorecard demo definition [Task: 6573109](https://www.odoo.com/odoo/2328/tasks/6573109) https://github.com/odoo/o-spreadsheet/commit/38daa1408d [FIX] pivot: wrong running total with collapsed/hidden dimensions [Task: 6569607](https://www.odoo.com/odoo/2328/tasks/6569607) https://github.com/odoo/o-spreadsheet/commit/2539ffbdb2 [FIX] pivot: fix scope of `pivot_html_renderer` css [Task: 6523521](https://www.odoo.com/odoo/2328/tasks/6523521) Co-authored-by: Florian Damhaut (flda) <flda@odoo.com> Co-authored-by: Anthony Hendrickx (anhe) <anhe@odoo.com> Co-authored-by: Alexis Lacroix (laa) <laa@odoo.com> Co-authored-by: Lucas Lefèvre (lul) <lul@odoo.com> Co-authored-by: Adrien Minne (adrm) <adrm@odoo.com> Co-authored-by: Ronak Mukeshbhai Bharadiya (rmbh) <rmbh@odoo.com> Co-authored-by: Dhrutik Patel (dhrp) <dhrp@odoo.com> Co-authored-by: Rémi Rahir (rar) <rar@odoo.com> Co-authored-by: Pierre Rousseau (pro) <pro@odoo.com> Co-authored-by: Vincent Schippefilt (vsc) <vsc@odoo.com> Co-authored-by: Marceline Thomas (matho) <matho@odoo.com>
A redundant internal step was removed from maintenance request creation. This cleanup has no expected impact on users, because the maintenance team is already assigned automatically when needed.
Original PR description
The create method assigned request.maintenance_team_id to itself, a no-op that reads and writes the same value and has no effect. This line originally set the team from the equipment as a fallback when creating a request. PR #196181, while refactoring mail alias handling from equipment category to team, replaced that assignment with a self-assignment, turning it into dead code. maintenance_team_id is a required field and is already a stored compute depending on equipment_id, so it is computed correctly on create without this line. Removing it has no functional impact. Forward-Port-Of: odoo/odoo#286132
Invoices already sent through PEPPOL can no longer have the PEPPOL sending option selected again. This prevents users from accidentally attempting to resend invoices that were already transmitted and makes the disabled status clearer in the interface.
Original PR description
If the invoice is already sent through PEPPOL, the checkbox for sending the invoice should then be readonly and unchecked. Currently is correctly unchecked but not readonly. We fix it by copying what French localization (`l10n_fr_pdp`) does already, giving a reason for disabling. <img width="1359" height="948" alt="immagine" src="https://github.com/user-attachments/assets/6f91ab34-8989-487e-8cd9-96dafee7bcb5" /> . Pad: https://pad.odoo.com/p/accountingv20 pad-accountingv20 Forward-Port-Of: odoo/odoo#288898
The API documentation now opens the correct related model when users middle-click a many-to-one field. This prevents confusion and saves time by taking users directly to the intended reference page without unnecessary reloads.
Original PR description
Steps to reproduce: * open api_doc * select a model (eg: project.task) * middle click on a many2one field (eg: stage_id) Observed behavior: The new tab is opened on the base model (project.task) instead of the comodel (project.task.type). This commit fixes the issue by using `t-att-href` to point to the correct model and `preventDefault` to avoid a full reload when clicking on a m2o. Forward-Port-Of: odoo/odoo#288558
The stock workflow test now recognizes the customized Turkish e-Dispatch stock list view, preventing false test failures when that localization is installed. This keeps quality checks reliable without changing the user-facing stock workflow.
Original PR description
### Steps to reproduce: - Install `l10n_tr_nilvera_edispatch` (e.g. the `tr` country build) - Run `test_basic_stock_flow_with_minimal_access_rights` > The tour times out on step 6/31, "check that at…
### Steps to reproduce: - Install `l10n_tr_nilvera_edispatch` (e.g. the `tr` country build) - Run `test_basic_stock_flow_with_minimal_access_rights` > The tour times out on step 6/31, "check that at least one picking is present in the view". ### Cause of the issue: The step triggers on `.o_stock_list_view_view`, a class the web client derives from the `js_class` of `stock.vpicktree`: https://github.com/odoo/odoo/blob/71c040ae236c9487afc49559486a588f21ccb37b/addons/stock/views/stock_picking_views.xml#L66-L70 https://github.com/odoo/odoo/blob/71c040ae236c9487afc49559486a588f21ccb37b/addons/web/static/src/views/utils.js#L45-L68 `l10n_tr_nilvera_edispatch` overwrites that attribute to plug in its e-Receipt upload button, so the root carries `o_l10n_tr_edispatch_tree_view` instead and the trigger never matches: https://github.com/odoo/odoo/blob/71c040ae236c9487afc49559486a588f21ccb37b/addons/l10n_tr_nilvera_edispatch/views/stock_picking_views.xml#L4-L13 Only the class name changes: `L10nTrNilveraEdispatchListView` spreads `StockListView`, so the rendered list is identical. runbot-947260 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#288255
Connecting a bank feed no longer removes payment methods that users already configured on a bank journal. The sync only adds missing default payment options, helping businesses avoid losing tailored incoming and outgoing payment setup.
Original PR description
**Steps to reproduce:** - Install Accounting - Configure "Bank" journal: * Add several incoming payments * Add several outgoing payments - From Accounting dashboard, connect Bank (e.g. Odoo Bank Sync Demo) **Issue:** After bank sync, all the incoming/outgoing payments added on the Bank journal are removed. Only the default ones are re-created. **Solution:** Keep all the existing incoming/outgoing payments (i.e. payment method lines) and only create the default ones for the payment method types that don't exist. opw-6424407 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281658
This fixes a case where batch payments could remain marked as sent even after the underlying bill and payment were fully paid. Payment matching is now refreshed correctly, helping finance teams see accurate payment statuses without manual intervention.
Original PR description
A payment on a journal without outstanding account has no journal entry, so it is matched as soon as it is paid. When the bill it pays is reconciled later on, _compute_state turns it to 'paid', but assigning a field from within a compute doesn't notify the fields depending on it: is_matched stays False and any batch payment holding that payment stays in 'sent' state. Mark is_matched for recomputation explicitly, as 18.0 already does since d8de234. Steps to reproduce: - On the Bank journal, leave the outstanding account empty on the outbound payment method line - Post a vendor bill - Register a payment on it - Put that payment in a batch payment and validate the batch - Create a MISC entry and reconcile the bill with it - Issue: bill and payment are 'Paid' but the batch stays 'Sent'. Forward-Port-Of: odoo/odoo#288460
This fixes a small issue where an internal export validation problem could show the wrong type of error. The change helps ensure errors are reported correctly, making diagnosis and maintenance more reliable without changing business workflows.
Original PR description
The format was broken. `'{}:{}' % it` → `TypeError` instead of `AssertionError`.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#288836
Forward-Port-Of: odoo/odoo#288610Splitting an already approved expense that has a receipt no longer fails with an access error. The fix lets Odoo copy the existing receipt only as part of the split process, while still preventing normal attachment changes on approved expenses.
Original PR description
Steps to reproduce: ---------------------------------------- 1. Install the Expense module. 2. Create an expense with a receipt/attachment and approve it. 3. Try to split the approved expense using…
Steps to reproduce: ---------------------------------------- 1. Install the Expense module. 2. Create an expense with a receipt/attachment and approve it. 3. Try to split the approved expense using the "Split Expense" button. Observation: ---------------------------------------- An Access Error is raised: "You can't add attachments to an expense once it has been approved." Issue: ---------------------------------------- When splitting an approved expense, Odoo duplicates the original expense into multiple split parts. Since the original expense is already in the `approved` state, the newly created duplicate records also have `state == 'approved'`. During the split process, Odoo copies the attachments from the original expense to the newly created split records: https://github.com/odoo/odoo/blob/e696bc516c97bc7157d52c5dba0b42e7cb8bab48/addons/hr_expense/wizard/hr_expense_split_wizard.py#L59-L61 Because `copied_expense.state` is 'approved', the create method of `ir.attachment` triggers an AccessError via the security validation https://github.com/odoo/odoo/blob/e696bc516c97bc7157d52c5dba0b42e7cb8bab48/addons/hr_expense/models/ir_attachment.py#L23-L27 Solution: ---------------------------------------- Bypass the attachment restriction if the creation is initiated from the split wizard. It only bypasses the validation during the split operation, preserving the security constraints for normal user uploads to approved expenses opw-6373579 Forward-Port-Of: odoo/odoo#276139
This update ensures the Turkish Nilvera e-Dispatch module installs reliably by declaring a missing required dependency. It prevents installation failures in test or minimal setup scenarios without changing business workflows.
Original PR description
View 'l10n_tr_nilvera_edispatch.view_picking_form_inherit_l10n_tr_nilvera_edispatch' fails to install in single-module test skip auto_install because it depends on field stock.picking:country_code. That field is provided by module 'stock_account' which is not in the dependency path of the module. In normal install the module 'stock_account' is present through auto_install when both 'account' and 'stock' are installed. Adding the direct dependency on 'stock_account' is not a problem because the view crashes without it. 'stock_account' is available through the chain below. [l10n_tr_nilvera_edispatch] ──[depends]──> [stock] ──⚡[AUTOLOAD]──> [stock_account] [l10n_tr_nilvera_edispatch] ──[depends]──> [l10n_tr_nilvera] ──[depends]──> [l10n_tr] ──[depends]──> [account] ──⚡[AUTOLOAD]──> [stock_account] REF Runbot: https://runbot.odoo.com/odoo/error/946186 Forward-Port-Of: odoo/odoo#288683 Forward-Port-Of: odoo/odoo#285633
Mail plugin tokens can now stay valid for a configurable period, with a default of 7 days. This reduces how often users need to sign in to the Outlook-related plugin while keeping the tokens limited to the intended Outlook authentication endpoints.
Original PR description
Purpose ======= Allow customizing the expiration time of tokens, so users don't need to login everyday in the plugin. This is customized with a system parameter, with a default of 7 days. Those tokens are limited to endpoints `auth="outlook"`. Task-6466253 Forward-Port-Of: odoo/odoo#288572 Forward-Port-Of: odoo/odoo#287767
This fixes an issue where a data grid could appear empty after the page refreshed or rebuilt part of the interface while already scrolled down. The grid now recalculates immediately when its scroll area changes, reducing confusing blank screens and avoiding the need for users to scroll or resize the window to recover.
Original PR description
See commit messages for details. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281721
When helpdesk tickets are merged, related timesheets now keep the same sales order item as the destination ticket. This prevents inconsistent billing or reporting details after combining tickets that were linked to different sale order items.
Original PR description
Currently when you merge helpdesk tickets with differing sale order items, the sales order item listed on the timesheets of the source ticket is not updated to match the destination ticket's sales order item. This PR ensures uniformity bugfix-6473396 Forward-Port-Of: odoo/enterprise#131155 Forward-Port-Of: odoo/enterprise#129060
The accounting prediction logic now looks at the most recent previous entries instead of older records. This helps produce more relevant automated suggestions for accounting work, reducing the chance of inaccurate predictions based on outdated data.
Original PR description
This commit: https://github.com/odoo/enterprise/pull/38830/changes#diff-6f6931855e0903ff0d3f2b39bd5703ceaef9bdf9a516862b83f38d2d5b21a232 change the order of the predictive queries, removing the sorting order by date. Based on the current docstring: https://github.com/odoo/enterprise/blob/66682012145e5116ebec0183102bc5e930c2c343/account_accountant/models/account_move.py#L676 this is not correct, as we expect to retrieve the previous 100 entries, rather than the oldest ones. Correcting the query order ensures that the most recent entries are considered for predictive purposes. opw-6558929 Forward-Port-Of: odoo/enterprise#132022 Forward-Port-Of: odoo/enterprise#131731
This fix prevents certain migrated spreadsheets from showing or restoring incorrect version history. It detects affected histories and rebuilds them from the correct saved snapshot, reducing the risk of users accidentally breaking spreadsheet documents when restoring older versions.
Original PR description
…heet history Some spreadsheet can end up in a corrupted history state Original Data ⮕ no revision (XX) ⮕ Snapshot ⮕ Active Revisions and where the original data differ from the snapshot. XX: can…
…heet history Some spreadsheet can end up in a corrupted history state Original Data ⮕ no revision (XX) ⮕ Snapshot ⮕ Active Revisions and where the original data differ from the snapshot. XX: can occur after the script added https://github.com/odoo/upgrade/issues/6340. The migration script is supposed to rewrite the history of the spreadsheet when there are holes in the archived revisions continuity (eg. the history was original Data ⮕ rev **A** ⮕ rev **B** ⮕ rev **C** ⮕ snapshot ⮕ rev **D** and user deleted rev **B** for instance, the script deletes **A** and **C** and marks **D** as the very first revision). Version history was designed with the idea to replay every single revision that existed since the creation of the spreadsheet and apply it to the original data, and in case of missing revisions, in our example, B is missing, we detect the lack of continuity, we start from the snapshot, and replay every single revision since that snapshot. When the migration fixes the continuity, by deleting all the old revisions, and changing their order, we can no longer detect the lack of continuity and end up replay every available revision to the original data ,even though they are based on the snapshot. In that scenario, since the revisions will be applied on the original data but since they are based on the state of the snapshot only, the final state of the spreadsheet will be corrupted since a part of the . If a user then decides to restore the spreadsheet to the version they see in the version history (which is corrupted as mentioned) and the last snapshot is overwritten with the corrupted state, effectively breaking the spreadsheet. With this revision, we add a detection of this corrupted history state, in which case we enforce the history to be replayed from the snapshot and not the original data. Task-6533708 Forward-Port-Of: odoo/enterprise#131803 Forward-Port-Of: odoo/enterprise#130649
This fixes the Colombian Libro Diario report so comparison views no longer trigger server errors. It also ensures legally required journal entries without a partner are included and displayed with consistent report headers.
Original PR description
## [FIX] l10n_co_reports: fix UNION ALL crash with multiple column groups ### Issue: Any comparison mode (Period, Analytic, etc.) in the Libro Diario raises an Odoo Server Error ### Cause: Each…
## [FIX] l10n_co_reports: fix UNION ALL crash with multiple column groups
### Issue:
Any comparison mode (Period, Analytic, etc.) in the Libro Diario raises an Odoo Server Error
### Cause:
Each sub-query in the `UNION ALL` had its own `ORDER BY` SQL only allows one global `ORDER BY` on a `UNION ALL`, or parentheses around each query — neither was the case
### Steps to reproduce:
- Install `l10n_co_reports` and `accountant`
- Enable Developer Mode in Settings
- Open the Libro Diario report and click the gear icon (top right)
- In the Options tab, enable Period Comparison
- Enable the Comparison for the Previous Period
Before the fix, an error is raised
------------------------------
## [FIX] l10n_co_reports: include partnerless entries in Libro Diario
### Issue:
Journal entries without a partner are excluded from the report but are legally required to appear
### Cause:
`_get_domain` called `super()` which adds `('partner_id', '!=', False)` to the domain, filtering out all partnerless entries
The SQL query also used a `JOIN` instead of `LEFT JOIN` on `res_partner`, excluding lines with no partner at the DB level
### Notes:
`NULL` values for `partner_name` or `line_label` caused the JS to hide the corresponding column headers
`header.js` matches columns to their header by `column_group_index`/`expression_label` and skips `None` values
Fixed by using `COALESCE` to return an empty string instead
### Steps to reproduce:
- Install `l10n_co_reports` and `accountant`
- Create a Journal Entry without a partner or label
- Open the Daily Journal Report
Before the fix, the entry doesn't appear
After the fix, check that PARTNER and LABEL headers are visible
opw-6430728
Forward-Port-Of: odoo/enterprise#131824
Forward-Port-Of: odoo/enterprise#129674Creating an appointment event from the calendar now respects the time slot the user selected instead of automatically using the appointment type's default duration. This helps avoid incorrectly timed bookings and reduces manual corrections for staff managing appointments.
Original PR description
When creating an event from the calendar view of an appointment type, the duration of the event was set to the duration of the appointment, therefore bypassing the slot we drew. This commit fixes this behavior by giving the priority to the end date of the drawed slot. Task-6412432 Forward-Port-Of: odoo/enterprise#130171
This fix ensures AI-generated pivot tables apply column groupings in the format the reporting view expects. It prevents errors or incorrect layouts when date-based grouping options are returned by the AI assistant.
Original PR description
The AI backend returns column groupbys as a list containing both strings and dictionaries with interval information. While this format is used to preserve the interval metadata, the pivot model expects `colGroupBys` to be a flat list of strings. This commit updates the view patch to flatten dictionary entries into their corresponding `<field>:<interval>` strings before assigning them to the pivot model metadata, ensuring the format matches the pivot model's expectations. task-6377810 Forward-Port-Of: odoo/enterprise#129515
Payments in the Mexican electronic invoicing module now use the payment method configured on the selected bank journal instead of always defaulting to electronic transfer. This helps ensure payment complements sent to the tax authority reflect the actual payment method, reducing compliance errors and manual corrections.
Original PR description
Currently, payment way configured on a bank journal is not taken into account, payments will default to "03 Transferencia electrónica de fondos". Steps to reproduce: - Set the "Payment Way" of a bank journal to "04 Tarjeta de Crédito". - Manually create a customer payment in that journal - Look at the "Payment Way" of the payment, then send the payment complement (REP) to the SAT. Issue: The payment way is "03 Transferencia electrónica de fondos" and the REP carries FormaDePagoP="03" The one set on the journal is ignored. Analysis: We should evaluate the journal before the transferencia default so a payment inherits the payment way, and keep transferencia as the last possible value. opw-6493514 Forward-Port-Of: odoo/enterprise#130863 Forward-Port-Of: odoo/enterprise#130133
The Ecuadorian ATS tax export now consolidates information from a company and its branches that share the same RUC. This ensures submitted XML files include all relevant invoices and totals, matching the tax dashboard and reducing reporting errors.
Original PR description
In Ecuador, a company and its branches file under a single RUC, so the ATS is expected to consolidate all of them. However, currently the system exports only the active company report. Steps to…
In Ecuador, a company and its branches file under a single RUC, so the ATS is expected to consolidate all of them. However, currently the system exports only the active company report. Steps to reproduce: - Install the Ecuadorian localization - Create a parent company and a branch, assign the RUC of the parent to the branch, and set the legal name of the branch in Settings - Post a customer invoice with taxes in the parent (e.g. 750) and another one in the branch (e.g. 250) - Activate both companies in the company selector - Go to Accounting > Reporting > Tax return - Select "Report: 104 (EC)", the dashboard shows the consolidated values - Click on the gear icon next to "Tax Return" and select ATS Issue: The exported XML only contains the documents and the totals of the parent company (750). The branch (250) is omitted. Analysis: Currently the ATS export use self.env.company for all searches, which only retrieve the data of the first company set opw-6469807 Forward-Port-Of: odoo/enterprise#128430
Fixes Argentinian electronic export invoices so item quantities use the correct decimal precision instead of being rounded too early. This prevents valid invoices with small fractional quantities from being rejected by ARCA after upgrades to version 19.0.
Original PR description
### Problem `l10n_ar_edi` reports WSFEX / WSBFE line quantities (`Pro_qty`) truncated to 2 decimals in 19.0, no matter what precision the database has configured. `_get_line_details()` reads the…
### Problem
`l10n_ar_edi` reports WSFEX / WSBFE line quantities (`Pro_qty`) truncated to 2 decimals in 19.0, no matter what precision the database has configured.
`_get_line_details()` reads the precision like this:
```python
uom_precision_digits = min(self.env['decimal.precision'].precision_get('Product Unit of Measure'), 2)
```
In 19.0 that `decimal.precision` record was renamed to **`Product Unit`** (`uom/data/uom_data.xml`, `decimal_product_uom`), so the lookup matches no record. `precision_get` does not raise in that case, it falls back to a default of 2 (`base/models/decimal_precision.py`: `return res[0] if res else 2`), so `min(2, 2) = 2`.
The rename was applied everywhere else — `account.move.line.quantity` already declares `digits='Product Unit'`. Only this lookup kept the old name.
### Impact
A quantity of `0.042` is sent as `0.04`. ARCA rejects the invoice with **error 1815** (item math inconsistency: `unit price x quantity - discount` no longer matches the item total), which blocks export invoicing completely.
It only shows up after upgrading to 19.0: on 18.0 the record still had the old name, so the lookup worked and the configured precision was used.
On our hosted fleet we identified **67 Argentinian databases** that use WSFEX or WSBFE and have a unit precision above 2. Eight of them already run 19.0 and are affected today; the rest will hit the same rejection as they upgrade.
### Fix
Use the current record name, and raise the cap to **6**, the maximum `Pro_qty` accepts according to the WSFEX developer manual ([V3.1.1](https://www.afip.gob.ar/ws/documentacion/manuales/WSFEX-Manualparaeldesarrollador_V3.1.1_ARCA.pdf), p. 15).
### Test plan
`l10n_ar_edi/tests/test_fex.py` adds `test_ar_edi_wsfex_pro_qty_decimal_precision`, covering three cases:
| `Product Unit` | quantity | expected `Pro_qty` |
|---|---|---|
| 3 | 0.042 | `0.042` |
| 2 | 0.042 | `0.04` |
| 8 | 0.1234567 | `0.123457` (capped at 6) |
It does not go through the ARCA mock: it calls `_get_rounded_base_and_tax_lines()` and `_get_line_details()` directly.
### Note
Supersedes #130582 by the same author, which carried the same one-line fix without a test. Please review this one instead.
### Left out on purpose
`price_precision_digits` in the same method caps the unit price at 3 digits, which does not come from the specification either. That lookup still uses a record name that exists (`Product Price`), so there is no regression, and we have no rejection reported because of it. Changing it would widen the scope of a fix that has a concrete incident behind it, so it is left untouched here.
Forward-Port-Of: odoo/enterprise#131457Submitting a draft Denmark VAT report no longer fails because the report now receives the required prior options when calculating lines. This helps Danish accounting users complete VAT submissions without being blocked by an application error.
Original PR description
Currently, an error occurs when the user submits the draft Denmark VAT report. ``` TypeError: AccountReport.get_options() missing 1 required positional argument: 'previous_options' ``` When the user submits the draft Denmark VAT report, it gets the calculated lines of the current report by calling get_options method. However, get_options() requires the previous_options argument [1]. Since this argument is not passed [2], it raises the error. This commit ensures that an empty dictionary is passed as the previous_options argument when getting the report lines. [1]- https://github.com/odoo/enterprise/blob/e2aa3073dafa9377654c761e371a660415db1e88/account_reports/models/account_report.py#L2126 [2]- https://github.com/odoo/enterprise/blob/e2aa3073dafa9377654c761e371a660415db1e88/l10n_dk_reports/wizard/tax_report_wizard.py#L216 sentry-7380293202 Forward-Port-Of: odoo/enterprise#130320
Financial reports now scroll correctly on iPhone and iPad, preventing the scroll indicator from being hidden behind report content. This makes long reports, such as tax reports, easier and more reliable to use on mobile devices without affecting desktop behavior.
Original PR description
### Issue: On iPhone and iPad (reduced window), the scrollbar is hidden behind the report on long scrollable pages This affects all browsers on iOS and iPadOS — Apple forces the use of WebKit (its…
### Issue: On iPhone and iPad (reduced window), the scrollbar is hidden behind the report on long scrollable pages This affects all browsers on iOS and iPadOS — Apple forces the use of WebKit (its rendering engine) on all of them, including Chrome and Firefox ### Steps to reproduce (on iPhone): - Install `l10n_es` (contains scrollable reports by default) - Switch to the ES company - Open the Tax Report and try to scroll Before the fix, the scrollbar renders behind the report content ### Cause: `o_content` was added unconditionally in commit https://github.com/odoo/enterprise/commit/d60ea6e0f3245e394fd0cee5f22f52aff2a79e2e But its role differs between desktop and mobile, and its presence on mobile triggers a WebKit compositor bug On desktop, `o_content` is required: `.o_action` stays `overflow: hidden`, so only `.o_content` (`overflow: auto`) can scroll the report Per the CSS flexbox spec, a flex item won't shrink below its content size unless its `overflow` is not `visible` Without `o_content`, the div keeps `overflow: visible`, refuses to shrink, overflows `.o_action`, and the excess is silently clipped — content becomes unreachable, not just visually different On mobile, the framework flips scroll responsibility to `.o_action` (`overflow: auto`) and forces `.o_content` back to `overflow: initial` `o_content` is therefore not needed on mobile On WebKit (iOS/iPadOS), keeping `o_content` on mobile is harmful: it sits as a non-scrolling `position: relative` node between the real scroll ancestor (`.o_action`) and descendants that require special compositing — the sticky `thead` and the fixed-position mobile chatter This configuration causes WebKit's compositor to miscalculate the Root layer bounding box This geometry mismatch is the most likely explanation for why the native scroll indicator renders behind the report instead of on top of it Removing `o_content` on mobile avoids this node entirely and restores correct compositor geometry ### Notes: Tested on Android (Blink) with and without `o_content`: no visual difference and identical compositor layer geometry confirmed via Chrome DevTools — no regression introduced The `padding-bottom` on `.o_account_report_scroll_container` is unrelated — it is applied unconditionally and exists for a separate bug (last row clipped on scroll) opw-6191827 Forward-Port-Of: odoo/enterprise#128528
This fix prevents planned field service hours from changing unexpectedly when a shift has multiple assigned resources and its project is edited. It keeps allocated time consistent, helping teams rely on planning data for scheduling and billing decisions.
Original PR description
1. Install Field Service and create a quotation with a service generating hours to plan, then confirm it 2. Click on the "To Plan" smart button and plan the hours 3. Open the planned shift and assign…
1. Install Field Service and create a quotation with a service generating hours to plan, then confirm it 2. Click on the "To Plan" smart button and plan the hours 3. Open the planned shift and assign a second resource to it 4. Change the "Project" of the shift several times -> the "Allocated Time" changes at every attempt The break time of a shift is the one of a single resource, while its allocated hours are the sum of the hours of all its resources. Both are mixed together when computing the break time and the allocated percentage, so as soon as a shift covers time outside of the schedule of its resources, the allocated percentage no longer matches the allocated hours it was computed from. As these two fields depend on each other, every recomputation then moves the allocated hours a bit further. With this commit, the allocated hours are divided by the number of assigned resources wherever they are compared to the break time, which keeps them stable whatever the number of resources. Task-6511322