Friday, September 4, 2026
35 changes · 19.0
Enhancements to existing features
The web debug dialog now includes a one-click option to copy the fully computed view structure. This helps consultants, support teams, and developers share or compare view details more reliably without manually selecting long XML text.
Original PR description
Description of the issue/feature this PR addresses: The "Computed Arch" debug dialog displays the fully computed view architecture, after inheritance, xpaths and studio customizations have been…
Description of the issue/feature this PR addresses: The "Computed Arch" debug dialog displays the fully computed view architecture, after inheritance, xpaths and studio customizations have been applied, in a read-only pre block. Extracting that text previously required manually selecting it in the browser, which is unreliable for long or deeply indented XML. Being able to copy this text to the clipboard helps with several common scenarios: - Debugging inherited views: when a view looks wrong and it is not clear which of several inheriting modules caused it, the computed arch can be diffed against the base view's arch to see exactly what changed. - Writing new xpath inherit rules: the exact final structure (attribute values, node ordering) is needed to write a correct expr="//field[@name='x']", which is easier to do in a scratch file or editor with search than by eyeballing a read-only dialog. - Bug reports and support tickets: the computed arch can be pasted into a Slack message, GitHub issue or support ticket so others can inspect the view without needing access to the database. - Studio customizations: consultants often need the underlying computed arch to understand why a Studio-added field appears in an unexpected position. - Comparing environments: the arch from a customer's staging instance can be diffed against production to spot config drift, e.g. a view customization made directly on prod. Current behavior before PR: In the "Computed Arch" debug dialog, the only way to get the arch text out of the browser is to manually click-drag to select it inside the pre block, then copy it. This is error-prone for long or deeply indented XML, where whitespace and line breaks are easy to select incorrectly or truncate. Desired behavior after PR is merged: A "Copy Arch" button is added next to "Close" in the dialog's footer. Clicking it copies the full computed arch to the clipboard in one click, with a brief "Copied" confirmation, removing the need to manually select the text. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Updates Finland’s mid-rate VAT from 14% to 13.5% to reflect the upcoming tax rate change. This helps Finnish accounting, invoicing, and tax reporting stay compliant with the new rate.
Original PR description
VAT rate for mid rate will change from 14% to 13.5% task-6517918
Resolved issues and error corrections
The SAF-T export now excludes current asset journal entries that previously caused the report generation to fail. This helps Norwegian companies produce the required audit file reliably when their general ledger includes these accounts.
Original PR description
Currently, an error occurs when generating the SAF-T report for a journal entries with the `asset_current` account type. **Steps to reproduce:** - Install `l10n_no_saft` and `accountant` modules and…
Currently, an error occurs when generating the SAF-T report for a journal entries with the `asset_current` account type. **Steps to reproduce:** - Install `l10n_no_saft` and `accountant` modules and switch to a NO Company. - Go to Contacts and set the ZIP code and state, then add a contact for the NO Company record. - Create a new Journal Entry, click `Add a line`, and set an account of type `Current Assets` (e.g., `1000 Development, acquired`) with the partner set to the NO Company. - Navigate to Reporting > General Ledger. - Click the gear icon and select `SAF-T`. **Error:** `KeyError: 'accounts'` **Root Cause:** At [1], from `19.0`, `asset_current` was mistakenly included in the second-to-last account type condition of the domain. As a result, partners linked to `asset_current` accounts are included in the `customer_vals_list` at [2]. However, `_l10n_no_saft_get_partners_accounts()` at [3] does not retrieve accounts of type `asset_current`. Therefore, when the `if` condition is not satisfied, the `accounts` key is not added to `partner_vals`. Since the partner has already been added to `customer_vals_list` at [2], the SAF-T template at [4] later tries to access `partner_vals['accounts']` when generating the `BalanceAccount` nodes, resulting in the error. **Fix:** This commit prevents the error by removing `asset_current` from the domain, similar to previous versions. [1]: https://github.com/odoo/enterprise/blob/1d49c3731ece1549a7a168bb479773ea279322bd/account_saft/models/account_general_ledger.py#L307-L313 [2]: https://github.com/odoo/enterprise/blob/1d49c3731ece1549a7a168bb479773ea279322bd/account_saft/models/account_general_ledger.py#L356-L362 [3]: https://github.com/odoo/enterprise/blob/1d49c3731ece1549a7a168bb479773ea279322bd/l10n_no_saft/models/account_general_ledger.py#L37-L42 [4]: https://github.com/odoo/enterprise/blob/1d49c3731ece1549a7a168bb479773ea279322bd/l10n_no_saft/data/saft_report.xml#L27-L37 opw-6441743
The documentation for temporary records now accurately explains that standard access rights and record rules apply. This prevents misunderstandings for implementers and administrators relying on the documentation to understand data access behavior.
Original PR description
Since 6d8688bb124d, TransientModel records use the regular access rights mechanisms instead of being implicitly restricted to their creator. The docstring was not updated with that change and has therefore incorrectly documented creator-only access since 14.0. Forward-Port-Of: odoo/odoo#286374 Forward-Port-Of: odoo/odoo#286251
Delivery slips now show rounded quantities when receipts or deliveries are split across multiple stock move lines. This prevents confusing decimal artifacts on printed documents and keeps ordered, delivered, and packaging quantities readable for customers and staff.
Original PR description
**Issue** When a move has several move lines, the printed quantities are not rounded, causing floating-point arithmetic artifacts to appear on the report. **Steps to reproduce** - Create and confirm…
**Issue** When a move has several move lines, the printed quantities are not rounded, causing floating-point arithmetic artifacts to appear on the report. **Steps to reproduce** - Create and confirm a PO for 15.6 units of a product. - On the receipt, change the quantity to 17.8 (this splits it into two stock move lines). - Validate the receipt and print the delivery slip. -> The ordered quantity on the generated PDF is not rounded (floating-point arithmetic issue). **Cause** While printing the delivery slip, quantities are aggregated by product: https://github.com/odoo/odoo/blob/189df3538aa07d22f683008522b9143421f411a2/addons/stock/report/report_deliveryslip.xml#L174 No rounding is performed while subtracting quantities from the ordered quantity (resulting in 13.399..): https://github.com/odoo/odoo/blob/189df3538aa07d22f683008522b9143421f411a2/addons/stock/models/stock_move_line.py#L927 Nor while adding the second move line's quantity back to the ordered quantity (resulting in 15.599..): https://github.com/odoo/odoo/blob/189df3538aa07d22f683008522b9143421f411a2/addons/stock/models/stock_move_line.py#L938 **Additional note** Same issues arise for `packaging_qty_ordered`, `quantity` and `packaging_quantity`. opw-6469422
The DHL REST shipping integration no longer creates a pickup request when arranging shipments. This aligns DHL with other carriers in Odoo and avoids extra scheduling steps and DHL errors when pickup windows are not configured.
Original PR description
Before this commit, the DHL REST module had the pick-up request set, which led to an unnatural use flow, needing to set up an scheduled date for pick-up, and several errors from DHL when these were not properly configured. This feature was unique to this module among the shipping carriers as we don't normally request pick-up for packages and leave it to user to decide how to do it. This commit removes the request for pick up and the logic that was needed to make it work. This will make the behavior consistent with other carriers in Odoo, and avoids the need to set scheduled pick-up windows and having to deal with unnecessary errors. opw-6148927 Forward-Port-Of: odoo/enterprise#123773
This fixes an issue in Planning where creating or editing multiple shifts in the Gantt view could fail when the default Employees filter was enabled. Managers can now use multi-edit reliably with that filter, reducing disruption during schedule planning.
Original PR description
## Step to reproduce: - Install Planning - Add "Employees" filter by default to a Gantt ## Result: The multi-create does not work because isManager does not resolve due to the early [return](https://github.com/odoo/enterprise/blob/0bee2f47c7e9d0b9a8d171fccde398a680a73415/planning/static/src/views/planning_gantt/planning_gantt_model.js#L60-L63) task-6535800
This update refreshes Odoo's spreadsheet component with several bug fixes that improve chart handling, pivot table ranges, formula recalculation, and editing stability. Users should see fewer crashes and more accurate spreadsheet results, especially when working with charts, pivots, and formulas.
Original PR description
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/39266880f2 [REL] 19.0.49 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0)…
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/39266880f2 [REL] 19.0.49 [Task: 0](https://www.odoo.com/odoo/2328/tasks/0) https://github.com/odoo/o-spreadsheet/commit/952d78083d [FIX] carousel: cannot add non-existing chart to carousel [Task: 6455790](https://www.odoo.com/odoo/2328/tasks/6455790) https://github.com/odoo/o-spreadsheet/commit/b12bb0cfd7 [FIX] svg: avoid rjsmin issue caused by nested template literals [Task: 6317134](https://www.odoo.com/odoo/2328/tasks/6317134) https://github.com/odoo/o-spreadsheet/commit/efec68bc83 [FIX] chart: fix funnel chart show value [Task: 6475094](https://www.odoo.com/odoo/2328/tasks/6475094) https://github.com/odoo/o-spreadsheet/commit/1b987bbbcd [FIX] pivot: unbounded ranges in the pivot side panel [Task: 6478220](https://www.odoo.com/odoo/2328/tasks/6478220) https://github.com/odoo/o-spreadsheet/commit/fc1dc64b80 [FIX] composer: crash when hovering a composer token [Task: 5153319](https://www.odoo.com/odoo/2328/tasks/5153319) https://github.com/odoo/o-spreadsheet/commit/baf19d7431 [FIX] evaluation: wrong dependencies invalidation with spread formulas [Task: 5103328](https://www.odoo.com/odoo/2328/tasks/5103328) 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>
Contact merges no longer copy the OCR-created marker from one contact to another. This prevents validation errors when merging duplicate contacts with the same name, making cleanup of OCR-created contacts smoother.
Original PR description
`is_created_by_ocr` identifies partners that were automatically created while processing an OCR document. A constraint prevents multiple partners with the same name to be created by OCR. But, when…
`is_created_by_ocr` identifies partners that were automatically created while processing an OCR document. A constraint prevents multiple partners with the same name to be created by OCR. But, when merging an OCR-created partner into a regular partner with the same name, the merge copies `is_created_by_ocr` to the destination before deleting the source partner. This temporarily leaves two active OCR partners with the same name and raises the unique constraint. Fix: `is_created_by_ocr` should have `copy=False` and should not be transferred when merging. Make the merge skip fields that are not copyable. This prevents the True value from being transferred to the destination, avoiding the unique constraint error. A test has been added in `account_invoice_extract` in enterprise, since `is_created_by_ocr` is only added to `res.partner` when that module is installed. Steps to Reproduce on Runbot: 1. Create 2 contacts with the same exact name and have one created by OCR. I used a server action to manually set the value of 'is_created_by_ocr' to simplify this process. 2. Select the contacts and merge. In the merge window, set the non-ORC contact to be the destination contact. 3. Upon confirming merge contacts, the validation error will appear. Related ticket: opw-6513607
Fixed an issue where the color picker could fail to recognize the solid color tab when Odoo was used in a translated language. This improves reliability for users working with the HTML editor across different locales.
Original PR description
### Purpose of this PR: - The color picker tabs are registered with a translated name (`_t(Solid)`), and the tab button renders that name as its only content. ColorUIPlugin read the active button's `innerHTML` and compared it to the literal string Solid to know whether the solid tab was the one in use. - Rely on the `solid-tab` class instead, which is built from the untranslated tab id. task-6441654
Reference fields now show a placeholder when a record still needs to be selected after choosing a model. This helps users notice incomplete links before saving, reducing confusion when values disappear after a page refresh.
Original PR description
Steps to reproduce: 1. Install Sign. 2. Open the form view of a document. 3. Select a model in the "Link to" (Reference) field, but leave the record empty. 4. Save and refresh the page. Issue: -…
Steps to reproduce:
1. Install Sign.
2. Open the form view of a document.
3. Select a model in the "Link to" (Reference) field, but leave the record empty.
4. Save and refresh the page.
Issue:
- After refreshing, the selected model is cleared because the reference value is invalid.
Cause:
- A reference field is only valid when it contains both a model and a record ID. However, the record selector has no placeholder, making it easy to overlook and save an incomplete value.
Solution:
- Add a default placeholder to the record selector of reference fields to make it more visible.
<table>
<tr>
<th>Before</th>
</tr>
<tr>
<td>
<img src="https://github.com/user-attachments/assets/3ba34b77-f901-4d3e-9768-5acaf2e673b8" alt="Before" width="100%">
</td>
</tr>
<tr>
<th>After</th>
</tr>
<tr>
<td>
<img src="https://github.com/user-attachments/assets/1fe54b89-221f-4d28-bd2b-0a3c706d5746" alt="After" width="100%">
</td>
</tr>
</table>
opw-6426339
Forward-Port-Of: odoo/odoo#280266The event booth registration page now ignores outdated loading results when visitors switch booth categories quickly. This prevents the wrong booth list from appearing and avoids failed registrations or the need to reload the page.
Original PR description
Before this commit, the "Get A Booth" page of an event could keep listing the booths of the category checked on load after the visitor picks another one. Only a page reload brought the right ones…
Before this commit, the "Get A Booth" page of an event could keep listing the booths of the category checked on load after the visitor picks another one. Only a page reload brought the right ones back. The tour webooth_exhibitor_register timed out on that list: FAILED: [5/13] Tour webooth_exhibitor_register -> Step Choose Booth (trigger: .o_wbooth_booths div:contains(OpenWood Demonstrator 2) input:not(:visible)). TIMEOUT step failed to complete within 10000 ms. This happens because the page fetches the booths of the category checked on load, and clicking another category fetches its booths while that first answer is still on its way. The answer coming back last fills the list, and the widget caches it under the category active on arrival, so the booths of the first category land in the cache of the clicked one. This commit fixes the issue by caching an answer under the category it was asked for, and by filling the list only while that category is still the chosen one. https://runbot.odoo.com/odoo/error/110527 https://runbot.odoo.com/odoo/error/161834 Forward-Port-Of: odoo/odoo#286552 Forward-Port-Of: odoo/odoo#286266
The Point of Sale no longer uses an older cleanup step that could remove more order data than necessary. A newer, more targeted fix now handles outdated loyalty reward lines, reducing the risk of unintended changes during checkout.
Original PR description
This fix is no longer required(https://github.com/odoo/odoo/pull/202752) as this one (https://github.com/odoo/odoo/pull/257043) is cleaner and less aggressive (it will only delete stale reward lines). This is the relevant part of the new fix to delete the previous one: https://github.com/odoo/odoo/pull/257043/changes#diff-18cef42f8c39513a82387e9cb81bc732b252304cd15b5b2f7b0b4623ac20cb41R100-R104 opw-6447092 Forward-Port-Of: odoo/odoo#286072 Forward-Port-Of: odoo/odoo#285376
This fix ensures the HTML editor properly removes file-related event handlers when an editor is closed or destroyed. It helps prevent gradual memory leaks and performance issues when users open multiple editor instances over time.
Original PR description
FilePlugin registered its click, keydown and pointerdown handlers with raw `addEventListener`, so they were never removed when the plugin was destroyed. The pointerdown one is bound to the document, which outlives the editable, leaking a handler per editor instance. Use `addDomListener` so Plugin.destroy() removes them. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286144
Merging a contact created from OCR into an existing contact with the same name no longer triggers a validation error. The OCR-created marker now stays with the original record only, allowing users to complete contact merges reliably.
Original PR description
`is_created_by_ocr` identifies partners that were automatically created while processing an OCR document. A constraint prevents multiple partners with the same name to be created by OCR. But, when…
`is_created_by_ocr` identifies partners that were automatically created while processing an OCR document. A constraint prevents multiple partners with the same name to be created by OCR. But, when merging an OCR-created partner into a regular partner with the same name, the merge copies `is_created_by_ocr` to the destination before deleting the source partner. This temporarily leaves two active OCR partners with the same name and raises the unique constraint. Fix: is_created_by_ocr should have copy=False and should not be transferred when merging. Make the merge skip fields that are not copyable. This prevents the True value from being transferred to the destination, avoiding the unique constraint error. A test has been added in `account_invoice_extract` in enterprise, since `is_created_by_ocr` is only added to `res.partner` when that module is installed. Steps to Reproduce on Runbot: 1. Create 2 contacts with the same exact name and have one created by OCR. I used a server action to manually set the value of 'is_created_by_ocr' to simplify this process. 2. Select the contacts and merge. In the merge window, set the non-ORC contact to be the destination contact. 3. Upon confirming merge contacts, the validation error will appear. Related ticket: opw-6513607
Users managing bank reconciliation models from a foreign currency bank statement will now see the correct models linked to that journal. This fixes a filtering issue caused by currency labels being added to journal names, helping accounting teams manage reconciliation rules without confusion or missing entries.
Original PR description
### Issue before this commit: When clicking "Manage Models" from a bank statement line, the associated reconciliation models are not displayed when belonging to a foreign currency journal. ### Steps…
### Issue before this commit: When clicking "Manage Models" from a bank statement line, the associated reconciliation models are not displayed when belonging to a foreign currency journal. ### Steps to reproduce the issue: 1. Download Accounting 2. Go to Currencies and activate another currency like EUR 3. Go to Journals and create a new one with bank type and curency EUR 4. Go to dashboard > new test bank journal created > 3 dots in the upper-right corner > Models > create a new one (ex Tester) setting the new test bank created as journal 5. Go to test bank journal and create a new bank matching 6. After the line is created click the 3 dots and go to Manage Models 7. See that the new model Tester created does not appear ### Cause of the issue: Foreign currency journals append their currency to the display_name (e.g., "Bank (EUR)"). The JS search framework passes this full decorated string into the search domain. The backend then attempts to match "Bank (EUR)" exactly in the database name and code fields, which fails because the database name is "Bank" without the currency added. https://github.com/odoo/odoo/blob/9c67949be529eb86886b3d5bde08e81e048ecfe7/addons/account/models/account_journal.py#L1095-L1100 ### Reason to introduce the fix: The filter is not working correctly. In this case it's better to change it to a domain instead of a default filter. opw-6481970
The website builder now correctly tracks changes to form field default values and translation field values so undo restores what users expect. This prevents stale values from remaining on the page after editing or switching date field types, reducing confusion while building websites.
Original PR description
The `value` property of the elements is not tracked by the history plugin, because `MutationObserver` does not produce mutations for that. This commit uses custom mutations when the `value` is changed, to restore the previous value on undo. Steps to reproduce: - Open website builder - Add a form - Set a "Default Value" on a text field - Press enter (to end preview) - Undo (with the button, or with focus out of the option's input) - Bug: The value shown in the page did not revert with undo Similar bug in translate mode task-6229671 Forward-Port-Of: odoo/odoo#281232
This fix prevents an accounting test from running in setups where the required Accountant app is not installed. It helps keep automated testing results accurate and avoids false failures that do not reflect a real customer issue.
Original PR description
This issue occurs because the `_is_user_able_to_review()` check returns `True` when the `accountant` module is not installed, which causes the `checked` field to be set to `True` in the `_compute_checked()` method. However, when the `accountant` module is installed, `_is_user_able_to_review()` is overridden and returns `False` for "Invoicing & Banks" users, causing the `checked` field to be set to `False` in `_compute_checked()`. Therefore, the `accountant` module needs to be installed when running the test. runbot-946621
Fixed an issue in the HTML editor where dragging an image and dropping it back in the same position could trigger an error, especially in Chrome. This improves editing reliability and prevents users from being interrupted while arranging images in content.
Original PR description
Steps to reproduce: - Insert an image as the last child of a paragraph. - Drag and drop it below or after itself. Description of the issue: - A traceback occurs. Cause: - When dropping an image below or after itself `document.caretPositionFromPoint()` computes a drop offset equal to the current node size. - The image is then removed from the DOM before being reinserted. Since it is the last child of its parent, removing it shrinks the parent, making the previously computed offset out of bounds. - Restoring the selection at that stale offset results in a traceback. Solution: - Treat dropping the image at its current position as a no-op and skip the remove/reinsert process, since it would not change the DOM. - Clamp the drop offset to the current node size before restoring the selection preventing out-of-bounds offsets. task-6435091 Forward-Port-Of: odoo/odoo#283680 Forward-Port-Of: odoo/odoo#280612
Rental order lines created from the rental schedule now use the normal product name instead of adding stock quantity text to the line description. Stock quantities still appear where useful in the schedule rows, reducing confusion while preserving planning visibility.
Original PR description
Versions -------- 19.0 and later Steps ----- - Install `sale_stock_renting`. - Go to Rental > Orders > Rental Schedule. - Create a new rental order line from a cell of the gantt view, on a row…
Versions -------- 19.0 and later Steps ----- - Install `sale_stock_renting`. - Go to Rental > Orders > Rental Schedule. - Create a new rental order line from a cell of the gantt view, on a row grouped by a storable rentable product. Issue ----- The first line of the description of the created line is named "Bike (3 items)" instead of "Bike". Cause ----- The `display_name` override adding that quantity is keyed on the `in_rental_schedule` context key. That key is set on the `action_rental_order_schedule` action itself, so it is part of the search context and is propagated to every record, dialog and dropdown opened from the schedule, while it is only meant to flag that we are in the schedule (default values conversion, hidden onchange buttons, group expansion, ...). Solution -------- Introduce a dedicated `display_renting_stock_quantity` context key and depend on it instead when fetching data to build the gantt rows, leaving the records opened from the schedule with their regular display name.
Refunds for valued products purchased in a foreign currency now avoid posting currency exchange differences to the stock valuation account when goods are returned. This keeps inventory valuation cleaner and prevents accounting distortions when exchange rates change between purchase and refund.
Original PR description
When refunding the purchase of a valued product that was received in a foreign currency. If the rate of the currency has changed between the purchase and the refund, the exchange difference line was impacting the valuation account. Steps to reproduce: ------------------- * Activate any other currency * Create a valued product and set a cost price * Create a purchase order in the foreign currency for the product * Confirm the purchase order and receive the product * Change the rate of the foreign currency * Create a return for the product and validate it > Observation: An exchange difference line is created and impacting the valuation account. Why the fix: ------------ When selecting the exchange account to use, we now check if we are in a return context. If it's he case we do not use the stock valuation account. opw-6313904 Forward-Port-Of: odoo/odoo#278047
Corrects a rounding mismatch in Mexican electronic invoicing payment complements for USD invoices paid in MXN. This prevents valid partial or exchange-rate-affected payments from being rejected by the certification provider with CRP20268.
Original PR description
**Steps to reproduce:** * Install the **l10n_mx** localization. * Enable **USD** and fetch the latest currency exchange rate from the settings. * Configure **Quadrum** as the **PAC** in the settings.…
**Steps to reproduce:**
* Install the **l10n_mx** localization.
* Enable **USD** and fetch the latest currency exchange rate from the settings.
* Configure **Quadrum** as the **PAC** in the settings.
* Create and sign a USD invoice with **16% IVA** (e.g. 4,500 USD + 720 USD tax = 5,220 USD total).
* Send the invoice to **CFDI**.
* Register a **partial MXN payment** that does not convert to a round USD amount (e.g. 30,000 MXN = 1,762.45 USD).
* Send the payment complement to the PAC by clicking **Update Payments** on the invoice.
**Observed behavior:**
The PAC rejects the CFDI with error **CRP20268**:
> El campo BaseP que corresponde a Traslado, no es igual a la suma de
> los importes de las bases registrados en los documentos relacionados
> donde el impuesto del documento relacionado sea igual al campo
> ImpuestoP de este elemento y la TasaOCuotaDR del documento
> relacionado sea igual al campo TasaOCuotaP de este elemento.
**Cause:**
* The SAT validator enforces a strict arithmetic relationship between three fields that are printed in the payment complement XML:
```
BaseP == round(BaseDR / EquivalenciaDR, 6)
```
* When `percentage_paid` is a non-terminating decimal (which happens for any partial MXN payment against a USD invoice), the internal `raw_base` float carries more precision than the 6-decimal-place `BaseDR` that is actually written to the XML:
```
percentage_paid = 1762.45 / 5220 = 0.33763409961685825...
raw_base = 4500 × 0.33763... = 1519.353448275862...
BaseDR (XML) = float_round(raw_base, 6) = 1519.353448
```
* The old code then used `raw_base` (the unrounded internal value) as the dividend when computing BaseP:
```
BaseP (old) = float_round(1519.353448275862... / 0.0587483333, 6)
= 25862.068980 ← written to <TrasladoP BaseP="...">
```
* The PAC performs the same division using only what it can read from the XML. The already-rounded BaseDR:
```
BaseP (PAC) = round(1519.353448 / 0.0587483333, 6)
= 25862.068975
```
* The 6th-decimal mismatch (25862.068980 ≠ 25862.068975) triggers CRP20268 and the document is rejected.
* The same issue occurs with a full MXN payment on a different date than the invoice when multiple invoice lines cause the rounded aggregate to diverge from the sum of per-line raw values.
**Fix:**
In `_l10n_mx_edi_add_payment_cfdi_values` (`account_move.py`), the block that builds the BaseP aggregation list was changed from iterating over raw per-`base_line` amounts to building a single synthetic entry per invoice using the already-rounded document-level `BaseDR` values (`tax_details['base']`) as the dividend:
- Before : wrong: raw_base ≠ BaseDR printed in the XML
'raw_base': tax_details['raw_base'] / inv_rate
- After : correct: 'base' == BaseDR, the exact value in the XML
'raw_base': tax_details['base'] / inv_rate
This guarantees that Odoo and the PAC divide the identical value, producing the identical 6-decimal result.
The `base_line_cfdi_values_mx_curr_list` path (used only for the `Totales` summary fields rounded to 2 dp) is left unchanged because the CRP20268 rule does not apply to that block.
opw-6468077
Forward-Port-Of: odoo/enterprise#128357This fix prevents electronic invoice generation from failing when the enterprise accounting add-on is not installed. It checks whether optional deferred billing date fields are available before using them, improving reliability for Community Edition users.
Original PR description
The fields `deferred_start_date` and `deferred_end_date` are created by the enterprise addon `account_accountant`, so not having it installed, this crashes with:
```
File "/opt/odoo/auto/addons/account_edi_ubl_cii/models/account_edi_cii.py", line 684, in <listcomp>
billing_start_dates += [move_line.deferred_start_date for move_line in invoice.invoice_line_ids if move_line.deferred_start_date]
AttributeError: 'account.move.line' object has no attribute 'deferred_start_date'
```
This PR protects the access to these fields checking first if they exist.
Bug introduced in the refactoring in #261572.
@Tecnativa TT64359
Forward-Port-Of: odoo/odoo#286245Vertical tabs in example setup dialogs now line up correctly, making the page easier to read. Longer tab names wrap neatly instead of disrupting the layout, which helps users navigate empty Project or UTM setup screens more reliably.
Original PR description
When a user opened a page with a vertical notebook, the tabs were not aligned with each other. Vertical notebooks should now have properly aligned tabs. If a tab title is too long, it will wrap onto the next line instead of breaking the layout. task-[5933892](https://www.odoo.com/odoo/project/4105/tasks/5933892) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fixes an issue where importing multiple Belgian SODA files at once could copy lines from the first file into the next accounting entry. Each imported file now keeps its own lines, helping avoid incorrect duplicate accounting data.
Original PR description
Due to this commit: https://github.com/odoo/enterprise/commit/93c05b380e3c939e3c0b44eafcd7a41e86042d2d When importing 2 sodas from drag and drop. Due to the placement of the line_ids variable, the second move would have the line of first. By placing the variable in the loop we don't have that problem anymore task-6528101
This fixes the display of vertical notebook tabs in dark mode so each tab is visually distinct. It improves readability and navigation for users working with pages that use this layout.
Original PR description
## Behavior Before the Commit When a user opens a page with a vertical notebook in dark mode, the different tabs aren't separate from one another. task-[5933892](https://www.odoo.com/odoo/project/4105/tasks/5933892)
The scheduled GST token refresh now correctly handles multiple companies instead of relying on a single company context. This helps ensure the next refresh is planned when any company token is successfully renewed, supporting more reliable GST reporting operations.
Original PR description
The `_cron_refresh_gst_token` method is called by a cron job. Previously, when scheduling the next cron execution, it checked `self.company_id.l10n_in_gstr_gst_token`. However, since the cron can process multiple companies, relying on `self.company_id` could result in incorrect behavior. In this commit, a flag is introduced to track whether at least one GST token was refreshed successfully. If a token was refreshed, the cron is scheduled to run again after 6 hours.
This update resolves several issues across Attendance, Accounting, Email, eCommerce, IoT, Sales, Website, and localizations. It helps users avoid blocked check-ins, installation crashes, missing email details, access errors, and incorrect localization behavior.
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
This fix ensures remaining hours on sales order lines for timesheet-based services are recalculated when relevant unit or availability details change. Businesses get more accurate project and service tracking without relying on manual refreshes or corrections.
Original PR description
The dependencies of _compute_remaining_hours do not match the fields actually used for the computation: it lists analytic_line_ids, which it never uses, and omits both remaining_hours_available, and product_uom. _compute_remaining_hours_available has the same issue: it uses product_uom but only depends on product_id.service_policy. analytic_line_ids, on the other hand, can be dropped: qty_delivered already depends on it, along with its so_line, unit_amount, product_uom_id and project_id, so the timesheet flow keeps triggering the recomputation. This PR fixes the dependencies for both aforementioned compute methods. Task-4748521 Forward-Port-Of: odoo/odoo#285685 Forward-Port-Of: odoo/odoo#284750
Odoo now handles requests with overly long web addresses more reliably. Instead of triggering an internal error while preparing the rejection response, the server safely returns the expected response, reducing noise and improving stability.
Original PR description
- When the request URI is too long, the HTTP server rejects the request before parsing the headers. As a result, `self.headers` is not available when the WebSocket compatibility code in `send_header()` and `end_headers()` is executed. - Access `self.headers` safely to avoid an AttributeError while handling the 414 response. **opw-6501275** --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286330 Forward-Port-Of: odoo/odoo#285870
Paid French electronic invoices now automatically include the required due date in exports. This helps invoices comply with the latest French validation rules and reduces the risk of rejected submissions.
Original PR description
According the schematron v1.4, the cbc:DueDate is required when the move is PAID. "[BR-FR-CO-09/BT-23] : Si le cadre de facturation (BT-23) est B2, S2 ou M2, alors la date d’échéance (BT-9) doit être renseignée et correspondre à la date de paiement." no-task --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#286263
Fixed an issue in the HTML builder where some applied design options could be ignored when their priority was below zero. This helps ensure the editor correctly recognizes the selected option in composite actions, improving reliability for website editing.
Original PR description
The function `useSelectableComponent` looked for the selected option by searching for the option with the highest priority among the options that are applied. The search for highest priority implicitely excluded options with negative priority. This case happens with `composite` action when the inner actions have no definition of `getPriority`. This commit initialize the "highest priority found so far" as `-Infinity` instead of 0. task-5245362 Forward-Port-Of: odoo/odoo#286503
This fix ensures that user-specific settings are respected during bank reconciliation quick creation. It prevents inconsistent behavior when automatic statement processing settings differ between the user's session and the global screen state.
Original PR description
Since this commit: https://github.com/odoo/enterprise/commit/938978c622700f9de097d9ff163f5b3c043231ed We pass the auto_statement_processing context key to false when destroying the component. The problem is that for the quick creation we use the model context. It might happen that those two contexts are different and can create inconsistancy. This commit will make sure the user context has priority on the global state context. no task id
This fix stops users from accidentally creating API keys that are already expired, such as when copying example dates from documentation. It helps avoid confusing login or integration failures caused by unusable keys.
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.
Selecting a suggested partner or company now correctly updates the form’s saved status after the record is enriched and saved. This prevents users from seeing save or discard buttons that appear active but do nothing, reducing confusion during partner entry.
Original PR description
Steps to reproduce: 1) open partner form view 2) type in the name field 3) select a suggestion from the autocomplete dropdown Issue: The record is enriched and saved, but the form still displays the save/discard buttons, and clicking them does nothing. The record dirty indicator is driven by 2 signals 1) `model.root.dirty`, which is cleared by save() call earlier in the onSelect() 2) the state `fieldIsDirty` of the `FormStatusIndicator` The second indicator is set to true when the user types in an input field, and selecting an option never clears it. The `setDirty` prop no longer exists, and therefore was deadcode. This commit emits `FIELD_IS_DIRTY` bus event, which is the only way to update the second indicator. With that, the indicator goes back to saved state once the record is updated. task-6475332 Forward-Port-Of: odoo/odoo#286268 Forward-Port-Of: odoo/odoo#285897